【BZOJ1135】[POI2009]Lyz 线段树

【BZOJ1135】[POI2009]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

题解:如果出现不够用的情况,那么一定是存在连续的一些人,他们把能穿的鞋子都穿完了还是不够,即存在l<r,且$(r-l+d+1)*k \le sum[l..r] $。

移项,得$sum[l..r]-(r-l+1)*k \ge d*k $,有没有看出什么?我们将所有数的权值-k,那么就变成了整个区间的最大连续子段和>=d*k。用线段树维护即可。

 

#include <cstdio>
#include <cstring>
#include <iostream>
#define lson x<<1
#define rson x<<1|1
using namespace std;
typedef long long ll;
int n,m;
ll K,D;
const int maxn=200010;
struct node
{
	ll s,lm,rm,sm;
	node() {s=lm=rm=sm=0;}
	node(ll a) {s=a,lm=rm=sm=max(a,0ll);}
	node operator + (const node &b)	const
	{
		node c;
		c.s=s+b.s;
		c.lm=max(lm,s+b.lm);
		c.rm=max(b.rm,rm+b.s);
		c.sm=max(rm+b.lm,max(sm,b.sm));
		return c;
	}
}s[maxn<<2];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
	return ret*f;
}
void build(int l,int r,int x)
{
	if(l==r)
	{
		s[x]=node(-K);
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,lson),build(mid+1,r,rson);
	s[x]=s[lson]+s[rson];
}
void updata(int l,int r,int x,int a,ll b)
{
	if(l==r)
	{
		s[x]=node(s[x].s+b);
		return ;
	}
	int mid=(l+r)>>1;
	if(a<=mid)	updata(l,mid,lson,a,b);
	else	updata(mid+1,r,rson,a,b);
	s[x]=s[lson]+s[rson];
}
int main()
{
	n=rd(),m=rd(),K=rd(),D=rd();
	int i,a,b;
	build(1,n,1);
	for(i=1;i<=m;i++)
	{
		a=rd(),b=rd(),updata(1,n,1,a,b);
		if(s[1].sm>K*D)	printf("NIE\n");
		else	printf("TAK\n");
	}
	return 0;
}//4 4 2 1 1 3 2 3 3 3 2 -1 

 

posted @ 2017-11-05 16:18  CQzhangyu  阅读(305)  评论(0编辑  收藏  举报