【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
1 3
2 3
3 3
2 -1
Sample Output
TAK
TAK
NIE
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 "); else printf("TAK "); } return 0; }//4 4 2 1 1 3 2 3 3 3 2 -1