[bzoj1135][线段树][Hall定理]Lyz

版权声明:蒟蒻写的..能不能吱一声呀 https://blog.csdn.net/Rose_max/article/details/84582812

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

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/84582812