题目大意:
初始时滑冰俱乐部有1到n号的溜冰鞋各k双。已知x号脚的人可以穿x到x+d的溜冰鞋。 有m次操作,每次包含两个数ri,xi代表来了xi个ri号脚的人。xi为负,则代表走了这么多人。 对于每次操作,输出溜冰鞋是否足够。
思路:
感觉挺不错的一道题,果然POI的题目质量确实不错。
显然这是人和鞋子的二分图匹配,然后我们要求人这一边是否有完备匹配,那就用Hall定理了。
Hall定理是指数级别的枚举,由于这一题的特殊性,人如果是连续的,鞋子也必定连续,如果两段不连续的人他们的鞋子连在了一起,那么我们不妨把中间的部分选满。如果有一个集合不满足条件,那么肯定是一段连续的人的集合不满足条件,所以就只要处理连续的就好了。
设尺寸
i
i
的人数为,那么我们就要判断
∑i=lrai≤(r−l+1+d)∗k
∑
i
=
l
r
a
i
≤
(
r
−
l
+
1
+
d
)
∗
k
是否成立就好了,然后一个很强的操作就是式子化为了
∑i=lr(ai−k)≤d∗k
∑
i
=
l
r
(
a
i
−
k
)
≤
d
∗
k
然后就只要用线段树来维护区间的最大连续子段和就好了。
/*=================================
* Author : ylsoi
* Algorithm : Hall & Segment_Tree
* Problem : bzoj1135
* Time : 2018.7.12
* ===============================*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;
using namespace std;
void File(){
freopen("bzoj1135.in","r",stdin);
freopen("bzoj1135.out","w",stdout);
}
template<typename T>T _max(T _,T __){return _>__ ? _ : __;}
const int maxn=2e5+10;
const ll inf=LLONG_MAX;
int n,m,k,d;
struct Segment_Tree{
#define mid ((l+r)>>1)
#define lc rt<<1
#define rc rt<<1|1
#define lson lc,l,mid
#define rson rc,mid+1,r
ll sum[maxn<<2],Maxl[maxn<<2],Maxr[maxn<<2],Max[maxn<<2];
void pushup(int rt){
sum[rt]=sum[lc]+sum[rc];
Maxl[rt]=_max(Maxl[lc],sum[lc]+Maxl[rc]);
Maxr[rt]=_max(Maxr[rc],sum[rc]+Maxr[lc]);
Max[rt]=_max(Maxr[lc]+Maxl[rc],_max(Max[lc],Max[rc]));
}
void build(int rt,int l,int r){
if(l==r)sum[rt]=Max[rt]=Maxl[rt]=Maxr[rt]=-k;
else build(lson), build(rson), pushup(rt);
}
void update(int rt,int l,int r,int pos,int x){
if(l==r){
sum[rt]+=x;
Max[rt]=Maxl[rt]=Maxr[rt]=sum[rt];
}
else{
if(pos<=mid)update(lson,pos,x);
else update(rson,pos,x);
pushup(rt);
}
}
}T;
int main(){
File();
scanf("%d%d%d%d",&n,&m,&k,&d);
T.build(1,1,n);
REP(i,1,m){
int u,v;
scanf("%d%d",&u,&v);
T.update(1,1,n,u,v);
if(T.Max[1]<=(ll)k*d)puts("TAK");
else puts("NIE");
}
return 0;
}