CF 338E, 线段树

这道题真是太伤节奏了,做完之后好几天没动弹了。

题目大意:给你两个数组a、b,a长b短,对于以a每个位置开头与b等长的连续子序列,我们询问是否有这样一个匹配方式让子序列每个数和b中每个数一一对应相加且和大于给定的常数h。

解:没有想明白,去看官解没弄懂出题人是怎么分块瞎搞的。搜了一下题解,发现有一个更巧妙的解法,首先我们对b排序不会影响到结果,然后对于某个数,他在排序后的b里的合法匹配方案一定是连续的一段,这样就转化成了线段问题。对于Bn(从小到大排序的B数组),我们可知必须子序列里有n个数和他匹配,对于Bn-1,必须至少有n-1个数(因为可以允许有一个数匹配不了,但是匹配到Bn 上),于是等价于给定的n个线段覆盖让每个位置上的线段数>1,>2,>3 ... >n,如果开头把每个位置数都设成-1,-2,-3...-n,那么就是问n线段覆盖上去之后是否存在最小值小于零的格子(有则说明没有合法匹配)。至此我们便把原问题转化成线段树可做的问题。

我大概yy了一下,貌似这个做法不能推广到区间资源分配上,因为这个问题的特殊性在于他是一个萝卜一个坑,而且合法的线段一定是延伸到n的。

  1 #include <cstdio>
  2 #include <string>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <cstring>
  7 #include <complex>
  8 #include <set>
  9 #include <vector>
 10 #include <map>
 11 #include <queue>
 12 #include <deque>
 13 #include <ctime>
 14
 15 using namespace std;
 16
 17 const double EPS = 1e-8;
 18
 19 #define ABS(x) ((x)<0?(-(x)):(x))
 20 #define SQR(x) ((x)*(x))
 21 #define MIN(a,b) ((a)<(b)?(a):(b))
 22 #define MAX(a,b) ((a)>(b)?(a):(b))
 23
 24 #define LSON(x) ((x)<<1)
 25 #define RSON(x) (((x)<<1)+1)
 26 #define LOWBIT(x) ((x)&(-(x)))
 27 #define MAXS 1111
 28 #define MAXN 222222
 29 #define VOIDPOINT 0
 30 #define LL long long
 31 #define OO 214748364
 32
 33 struct SegTree{
 34     int l[MAXN*4], r[MAXN*4], m[MAXN*4], minn[MAXN*4], lazy[MAXN*4];
 35     int gx, gy, gz;
 36     void set(int a = 0, int b = 0, int c = 0) {
 37         gx = a; gy = b; gz = c;
 38     }
 39     inline void updata(int kok) {
 40         minn[kok] = min(minn[LSON(kok)], minn[RSON(kok)]);
 41     }
 42     inline void pushDown(int kok) {
 43         if (l[kok] != r[kok]) {
 44             lazy[LSON(kok)] += lazy[kok];
 45             minn[LSON(kok)] += lazy[kok];
 46             lazy[RSON(kok)] += lazy[kok];
 47             minn[RSON(kok)] += lazy[kok];
 48         }
 49         lazy[kok] = 0;
 50     }
 51     void build(int kok, int ll, int rr) {
 52         l[kok] = ll; r[kok] = rr; lazy[kok] = 0;
 53         if (ll == rr) {
 54             minn[kok] = -ll;
 55             return ;
 56         }
 57         int mid = m[kok] = (ll + rr) >> 1;
 58         build(LSON(kok), ll, mid); build(RSON(kok), mid+1, rr);
 59         updata(kok);
 60     }
 61     void insert(int kok) {
 62         if (gx > gy) return ;
 63         if (gx <= l[kok] && r[kok] <= gy) {
 64             lazy[kok] += gz; minn[kok] += gz;
 65             pushDown(kok);
 66             return ;
 67         }
 68         if (lazy[kok])
 69             pushDown(kok);
 70         int mid = m[kok];
 71         if (gx <= mid) insert(LSON(kok));
 72         if (gy > mid) insert(RSON(kok));
 73         updata(kok);
 74     }
 75 } Tree;
 76
 77 int a[MAXN], b[MAXN], n, len, h;
 78
 79 int main() {
 80 //    freopen("test.txt", "r", stdin);
 81
 82     scanf("%d%d%d", &n, &len, &h);
 83     for (int i = 1; i <= len; ++i) scanf("%d", &b[i]);
 84     sort(b+1, b+1+len);
 85     Tree.build(1, 1, len);
 86     int ans = 0;
 87     for (int i = 1; i <= n; ++i) {
 88         scanf("%d", &a[i]); a[i] = h - a[i];
 89         a[i] = lower_bound(b+1, b+1+len, a[i]) - b;
 90         if (i < len) {
 91             Tree.set(a[i], len, 1);
 92             Tree.insert(1);
 93         }
 94     }
 95     for (int i = len; i <= n; ++i) {
 96         Tree.set(a[i], len, 1);
 97         Tree.insert(1);
 98         ans += Tree.minn[1] >= 0 ? 1: 0;
 99         Tree.set(a[i-len+1], len, -1);
100         Tree.insert(1);
101     }
102     printf("%d\n", ans);
103     return 0;
104 }

CF 338E

附上官解页面,以后有空要搞搞明白别人是怎么分块乱搞的:http://codeforces.com/blog/entry/8629

时间: 2024-08-13 21:01:07

CF 338E, 线段树的相关文章

CF 633G 线段树+bitset

大意是一棵树两种操作,第一种是某一节点子树所有值+v,第二种问子树中节点模m出现了多少种m以内的质数. 第一种操作非常熟悉了,把每个节点dfs过程中的pre和post做出来,对序列做线段树.维护取模也不是问题.第二种操作,可以利用bitset记录质数出现情况.所以整个线段树需要维护bitset的信息. 对于某一个bitset x,如果子树所有值需要加y,则x=(x<<y)|(x>>(m-y)) 一开始写挂了几次,有一点没注意到,因为我bitset直接全都是1000,而不是m,所以上

CF 498D 线段树

大意是有n段路,每一段路有个值a,通过每一端路需要1s,如果通过这一段路时刻t为a的倍数,则需要等待1s再走,也就是需要2s通过. 比较头疼的就是相邻两个数之间会因为数字不同制约,一开始想a的范围是2-6,处理这几个数字互相之间的关系,还是想岔了. 正解应当是开60个线段树,因为2-6的LCM是60,也就是所有数字模2-6,结果的循环节长度为60.所以如果从i到j,开始时刻如果为0,则答案一定与开始时刻为60相同. 第x个线段树某个节点范围如果是i和j,维护的便是开始时刻模60为x的情况下,从i

CF 446C 线段树

CF446C题意: 给你一个数列\(a_i\),有两种操作:区间求和:\(\sum_{i=l}^{r}(a[i]+=fib[i-l+1])\).\(fib\)是斐波那契数列. 思路 (一) \(fib[n] = \frac{\sqrt5}{5}\times [(\frac{1+\sqrt5}{2})^n-(\frac{1-\sqrt5}{2})^n]\) 有关取模.同余.逆元的一些东西: \(p = 1e9 + 9\) \(383008016^2 ≡ 5 (mod\;p)\) \(3830080

CF19D 线段树+STL各种应用

http://codeforces.com/problemset/problem/19/D Description Pete and Bob invented a new interesting game. Bob takes a sheet of paper and locates a Cartesian coordinate system on it as follows: point (0,?0) is located in the bottom-left corner, Ox axis

【线段树】【树状数组】【CF 121E】幸运数列

1922. [CF 121E]幸运数列 ★★★ 输入文件:cf121e.in 输出文件:cf121e.out 简单对比 时间限制:3 s 内存限制:256 MB [题目描述] 对于欧洲人来说,"幸运数"是指那些十进制只由4或7组成的数.财务员Petya需要维护一个支持如下操作的整数数列: add l r d - 表示将[l, r]区间内的所有数加上一个正整数d(). count l r - 统计[l, r]区间内有多少个"幸运数".() 请你帮助Petya实现它.

CF#52 C Circular RMQ (线段树区间更新)

Description You are given circular array a0,?a1,?...,?an?-?1. There are two types of operations with it: inc(lf,?rg,?v) - this operation increases each element on the segment [lf,?rg] (inclusively) by v; rmq(lf,?rg) - this operation returns minimal v

CF(438D) The Child and Sequence(线段树)

题意:对数列有三种操作: Print operation l,?r. Picks should write down the value of . Modulo operation l,?r,?x. Picks should perform assignment a[i]?=?a[i] mod x for each i (l?≤?i?≤?r). Set operation k,?x. Picks should set the value of a[k] to x (in other words

(困难) CF 484E Sign on Fence,整体二分+线段树

Bizon the Champion has recently finished painting his wood fence. The fence consists of a sequence of n panels of 1 meter width and of arbitrary height. The i-th panel's height is hi meters. The adjacent planks follow without a gap between them. Afte

Cf 444C DZY Loves Colors(线段树)

DZY loves colors, and he enjoys painting. On a colorful day, DZY gets a colorful ribbon, which consists of n units (they are numbered from 1 to n from left to right). The color of thei-th unit of the ribbon is i at first. It is colorful enough, but w