1. 程式人生 > >[bzoj1135][線段樹][Hall定理]Lyz

[bzoj1135][線段樹][Hall定理]Lyz

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

題解

是個二分圖模型
可以 m n 3 mn^3

硬做,然後就T的飛起,然後就hall定理
Hall定理
如果一個二分圖存在完備匹配
設起較小的集合為X,較大的為Y。則在X中任選K個點,都會找到至少K個點與他們相連(並集)
考慮如何判斷,直接列舉是 2 200000 2^{200000}
要一點貪心
鞋碼為x的人看作一個集合,顯然這個集合的點,要不都選或者要不都不選
因為他萌連的點是一樣的,選了一個的時候你肯定想讓這個K儘量大然後讓fail的可能變大
然後就可以變成選一些集合
深入挖掘一下,如果選了集合a,如果還要選下一個集合才能讓這個fail,這個集合肯定與a相鄰
因為如果選其他集合,要不就是與當前連了的範圍沒有交集,這樣如果要選那個集合的話其實之前的集合都不用選的…
有交集的話肯定就是想讓交集的補集儘量小了
所以選的都是相鄰的
那麼就可以變成一個柿子
l r a [ i ] < = ( r l + 1 + d ) K \sum_l^ra[i]<=(r-l+1+d)*K

劃一下就可以變成
l r ( a [ i ] K ) < = d K \sum_l^r(a[i]-K)<=d*K
然後就是個最大子段和
線段樹即可

#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;
}