1135: [POI2009]Lyz
1135: [POI2009]Lyz
https://lydsy.com/JudgeOnline/problem.php?id=1135
分析:
hall定理+线段树连续区间的最大的和。
首先转化为二分图的模型,然后根据hall定理
Hall定理:
此定理使用于组合问题中,二部图G中的两部分顶点组成的集合分别为X, Y, X={X1, X2, X3,X4,.........,Xm}, Y={y1, y2, y3, y4 ,.........,yn},G中有一组无公共点的边,一端恰好为组成X的点的充分必要条件是:
X中的任意k个点至少与Y中的k个点相邻。(1≤k≤m)
那么如果直接枚举子集的话肯定不行,如果满足了最劣的情况,那么也就全满足了,所以考虑如何求出最劣的情况。
假设当前有连续的k个人[l,r],他们对应的鞋子区间是[l,r+d],那么如果此时有l-1处有a[l-1]:如果a[l-1]>k,那么将l-1和[l,r]这些人数的区间合成[l-1,r]的时候,增加的人数大于鞋子的个数,一定比分开算劣,所以就合起来。否则a[l-1]<=k,合起来比现在优,那么就不合起来。
所以最劣的情况就是对a[i]-k,求最大的子段和。
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cmath> 6 #include<cctype> 7 #include<set> 8 #include<queue> 9 #include<vector> 10 #include<map> 11 using namespace std; 12 typedef long long LL; 13 14 inline int read() { 15 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 16 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 17 } 18 19 const int N = 200005; 20 21 struct Node{ 22 LL ls, rs, sum, mx; 23 }T[N << 2]; 24 LL a[N]; 25 26 void pushup(int rt) { 27 T[rt].ls = max(T[rt << 1].ls, T[rt << 1].sum + T[rt << 1 | 1].ls); 28 T[rt].rs = max(T[rt << 1 | 1].rs, T[rt << 1 | 1].sum + T[rt << 1].rs); 29 T[rt].sum = T[rt << 1].sum + T[rt << 1 | 1].sum; 30 T[rt].mx = max(T[rt << 1].rs + T[rt << 1 | 1].ls, max(T[rt << 1].mx, T[rt << 1 | 1].mx)); 31 } 32 void update(int l,int r,int rt,int p,LL x) { // LL x !!! 33 if (l == r) { 34 T[rt].ls = T[rt].rs = T[rt].sum = T[rt].mx = x; return ; 35 } 36 int mid = (l + r) >> 1; 37 if (p <= mid) update(l, mid, rt << 1, p, x); 38 else update(mid + 1, r, rt << 1 | 1, p, x); 39 pushup(rt); 40 } 41 int main() { 42 int n = read(), m = read(); LL k = read(), d = read(), mx = d * k; 43 n -= d; 44 for (int i = 1; i <= n; ++i) update(1, n, 1, i, -k); 45 while (m --) { 46 int p = read(), x = read(); 47 a[p] = a[p] + x; 48 update(1, n, 1, p, a[p] - k); 49 puts(T[1].mx <= mx ? "TAK" : "NIE"); 50 } 51 return 0; 52 }