题解 P3488 [POI2009]LYZ-Ice Skates
滑冰俱乐部初始有
1 到n 号码溜冰鞋各k 双,已知x 号脚的人可以穿x 到x + d 号码的鞋子。现在有
m 次操作,每次两个数r 、x ,表示r 号脚的人来了x 个,x 为负表示离开。对于每次操作,输出溜冰鞋是否足够。
很容易想到将人和溜冰鞋一起建二分图,傻瓜式连边,并对于每次操作都跑一遍最大流,但这时间复杂度显然爆炸!
由于题目只询问是否存在完美匹配,所以考虑使用 Hall 定理。
设
不妨将右侧常变量分离,则有:
于是我们动态维护所有区间
用线段树可以做到
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5;
ll n,m,k,d;
struct node1{
ll maxn,sum,qz,hz;
node1 (ll maxn=0,ll sum=0,ll qz=0,ll hz=0)
:maxn(maxn),sum(sum),qz(qz),hz(hz){}
}S;
struct node{
ll sum[N<<2],qz[N<<2],hz[N<<2],maxn[N<<2];
void pushup(int i){
sum[i]=sum[i<<1]+sum[i<<1|1];
qz[i]=max(qz[i<<1],qz[i<<1|1]+sum[i<<1]);
hz[i]=max(hz[i<<1|1],hz[i<<1]+sum[i<<1|1]);
maxn[i]=max(maxn[i<<1],max(maxn[i<<1|1],hz[i<<1]+qz[i<<1|1]));
}
void build(int i,int l,int r){
if (l==r){
sum[i]=qz[i]=hz[i]=maxn[i]=-k;
return;
}
int mid=l+r>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
pushup(i);
}
void add(int i,int l,int r,int pos,ll s){
if (l==r){
sum[i]+=s;
qz[i]+=s;
hz[i]+=s;
maxn[i]+=s;
return;
}
int mid=l+r>>1;
if (pos<=mid) add(i<<1,l,mid,pos,s);
else add(i<<1|1,mid+1,r,pos,s);
pushup(i);
}
// node1 query(int i,int l,int r,int ql,int qr){
// if (ql<=l&&r<=qr) return node1(maxn[i],sum[i],qz[i],hz[i]);
// int mid=l+r>>1;
// if (qr<=mid) return query(i<<1,l,mid,ql,qr);
// if (mid<ql) return query(i<<1|1,mid+1,r,ql,qr);
// node1 x=query(i<<1,l,mid,ql,qr),y=query(i<<1|1,mid,r,ql,qr),z;
// z.qz=max(x.qz,x.sum+y.qz);
// z.hz=max(y.hz,y.sum+x.hz);
// z.sum=x.sum+y.sum;
// z.maxn=max(max(x.maxn,y.maxn),x.hz+y.qz);
// return z;
// }
}T;
int read(){
int w=0,f=1;
char c=getchar();
while (c>'9'||c<'0'){
if (c=='-') f=-1;
c=getchar();
}
while (c>='0'&&c<='9'){
w=(w<<3)+(w<<1)+(c^48);
c=getchar();
}
return w*f;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
#endif
n=read(),m=read(),k=read(),d=read();
T.build(1,1,n);
for (int i=1;i<=m;i++){
int x=read(),g=read();
T.add(1,1,n,x,g);
ll num=T.maxn[1];
//cout<<num<<"\n";
if (num>k*d) puts("NIE");
else puts("TAK");
}
return 0;
}