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
Sample Output
TAK
TAK
NIE
TAK
这题好难,完全不懂原理……以下转载CRZbulabula的博客
Hall定理
把俱乐部的人看做点集X,溜冰鞋看做点集Y
显然这是一个二部图
根据Hall定理,如果存在饱和点集X的匹配,那么(forall S subseteq X),(|N(S)| geqslant |S|)
N(S)是Y中与X相邻的点的集合
对于此题,Hall定理最容易取到反例的状况一定是连续一段区间
因为此时能用来容纳X匹配的对应的Y总不多于不连续的区间
那么就是说,(forall sumlimits_{i=l}^r A_i leqslant (r - l + 1 + d) imes k)
两边同时-k,得(sumlimits_{i=1}^n (A_i-k) leqslant d imes k)
于是,我们只需要维护连续序列的最大值就行了
线段树解决
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x>=10) print(x/10);
putchar(x%10+'0');
}
const int N=2e5;
int n,m,k,d;
struct Segment{
#define ls (p<<1)
#define rs (p<<1|1)
struct node{
ll le,ri,sum,now;
node(){le=ri=now=sum=0;}
node(ll a,ll b,ll c,ll d){le=a,ri=b,sum=c,now=d;}
void insert(ll x){le=ri=now=sum=x;}
}tree[(N<<2)+10];
friend node operator +(const node &x,const int v){return node(x.le+v,x.ri+v,x.sum+v,x.now+v);}
friend node operator +(const node &x,const node &y){
node z;
z.now=max(max(x.now,y.now),x.ri+y.le);
z.le=max(x.le,x.sum+y.le);
z.ri=max(y.ri,x.ri+y.sum);
z.sum=x.sum+y.sum;
return z;
}
void build(int p,int l,int r){
if (l==r){
tree[p].insert(-k);
return;
}
int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
tree[p]=tree[ls]+tree[rs];
}
void change(int p,int l,int r,int x,ll v){
if (l==r){
tree[p]=tree[p]+v;
return;
}
int mid=(l+r)>>1;
if (x<=mid) change(ls,l,mid,x,v);
else change(rs,mid+1,r,x,v);
tree[p]=tree[ls]+tree[rs];
}
}Tree;
int main(){
n=read(),m=read(),k=read(),d=read();
Tree.build(1,1,n);
for (int i=1;i<=m;i++){
int x=read(),v=read();
Tree.change(1,1,n,x,v);
printf(Tree.tree[1].now>1ll*k*d?"NIE
":"TAK
");
}
return 0;
}