1135: [POI2009]Lyz
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 418 Solved: 191
[ Submit][ Status][ Discuss]
Description
初始时滑冰俱乐部有1到n号的溜冰鞋各k双。已知x号脚的人可以穿x到x+d的溜冰鞋。 有m次操作,每次包含两个数ri,xi代表来了xi个ri号脚的人。xi为负,则代表走了这么多人。 对于每次操作,输出溜冰鞋是否足够。
Input
n m k d ( 1≤n≤200,000 , 1≤m≤500,000 , 1≤k≤10^9 , 0≤d≤n ) ri xi ( 1≤i≤m, 1≤ri≤n-d , |xi|≤10^9 )
Output
对于每个操作,输出一行,TAK表示够 NIE表示不够。
Sample Input
4 4 2 1
1 3
2 3
3 3
2 -1
1 3
2 3
3 3
2 -1
Sample Output
TAK
TAK
NIE
TAK
TAK
NIE
TAK
HINT
Source
Hall定理,,,
把俱乐部的人看做点集X,溜冰鞋看做点集Y
显然这是一个二部图
根据Hall定理,如果存在饱和点集X的匹配,那么∀S ⊆ X,|N(S)| >= |S|
N(S)是Y中与X相邻的点的集合
对于此题,Hall定理最容易取到反例的状况一定是连续一段区间
因为此时能用来容纳X匹配的对应的Y总不多于不连续的区间
那么就是说,∀∑ai <= (r - l + 1 + d)*k, (i∈[l,r])
两边同时-k,得∑(ai-k) <= d*k
于是,我们只需要维护连续序列的最大值就行了
线段树解决
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 2E5 + 20;
const int T = 4;
typedef long long LL;
int n,m;
LL k,d,c[maxn*T],ml[maxn*T],mr[maxn*T],ma[maxn*T];
void maintain(int o)
{
int lc = (o<<1),rc = (o<<1|1);
c[o] = c[lc] + c[rc];
ma[o] = max(ma[lc],ma[rc]);
ma[o] = max(ma[o],mr[lc] + ml[rc]);
ml[o] = max(ml[lc],c[lc] + ml[rc]);
mr[o] = max(mr[rc],c[rc] + mr[lc]);
}
void Build(int o,int l,int r)
{
if (l == r) {
c[o] = ma[o] = ml[o] = mr[o] = -k;
return;
}
int mid = (l + r) >> 1;
Build(o<<1,l,mid);
Build(o<<1|1,mid+1,r);
maintain(o);
}
void Modify(int o,int l,int r,int pos,LL x)
{
if (l == r) {
c[o] += x; ma[o] += x;
ml[o] += x; mr[o] += x;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) Modify(o<<1,l,mid,pos,x);
else Modify(o<<1|1,mid+1,r,pos,x);
maintain(o);
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> n >> m >> k >> d;
Build(1,1,n);
while (m--) {
int r,x; scanf("%d%d",&r,&x);
Modify(1,1,n,r,x);
if (ma[1] > k*d) puts("NIE");
else puts("TAK");
}
return 0;
}