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

posted @ 2016-07-22 18:29  F.D.His.D  阅读(303)  评论(0编辑  收藏  举报