[bzoj1135][線段樹][Hall定理]Lyz
阿新 • • 發佈:2018-11-28
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
題解
是個二分圖模型
可以硬做,然後就T的飛起,然後就hall定理
Hall定理
如果一個二分圖存在完備匹配
設起較小的集合為X,較大的為Y。則在X中任選K個點,都會找到至少K個點與他們相連(並集)
考慮如何判斷,直接列舉是 的
要一點貪心
鞋碼為x的人看作一個集合,顯然這個集合的點,要不都選或者要不都不選
因為他萌連的點是一樣的,選了一個的時候你肯定想讓這個K儘量大然後讓fail的可能變大
然後就可以變成選一些集合
深入挖掘一下,如果選了集合a,如果還要選下一個集合才能讓這個fail,這個集合肯定與a相鄰
因為如果選其他集合,要不就是與當前連了的範圍沒有交集,這樣如果要選那個集合的話其實之前的集合都不用選的…
有交集的話肯定就是想讓交集的補集儘量小了
所以選的都是相鄰的
那麼就可以變成一個柿子
劃一下就可以變成
然後就是個最大子段和
線段樹即可
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define lc now<<1
#define rc now<<1|1
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(int x)
{
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);printf(" ");}
inline void pr2(int x){write(x);puts("");}
LL mx[210000*4],l1[210000*4],r1[210000*4],sum[210000*4];
void pushup(int now)
{
mx[now]=max(max(mx[lc],mx[rc]),r1[lc]+l1[rc]);
l1[now]=max(l1[lc],sum[lc]+l1[rc]);
r1[now]=max(r1[rc],sum[rc]+r1[lc]);
sum[now]=sum[lc]+sum[rc];
}
void modify(int now,int l,int r,int p,LL c)
{
if(l==r)
{
mx[now]+=c;l1[now]+=c;r1[now]+=c;sum[now]+=c;
return ;
}
int mid=(l+r)/2;
if(p<=mid)modify(lc,l,mid,p,c);
else modify(rc,mid+1,r,p,c);
pushup(now);
}
int n,m,K,D;
int main()
{
n=read();m=read();K=read();D=read();
for(int i=1;i<=n;i++)modify(1,1,n,i,-K);
while(m--)
{
int x=read(),pa=read();
modify(1,1,n,x,pa);
if(mx[1]<=(LL)D*K)puts("TAK");
else puts("NIE");
}
return 0;
}