BZOJ1135: [POI2009]Lyz
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1135
线段树+hall定理。。
设当前穿i号鞋子的人数是a[i],那么我们要保证∑a[i]≤(r-l+1+d)*k,让a[i]-=k,就变成了∑a[i]≤d*k
然后要让任何一段区间都满足这个条件,那么求最大连续子段和就可以了。
#include<cstring> #include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<queue> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define inf int(1e9) #define maxn 205000 #define mm 30031 #define ll long long using namespace std; int n,m; ll k,d; struct data{int l,r;ll ls,rs,ss,sum; }t[maxn*3]; int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x*f; } void build(int i,int l,int r){ t[i].l=l; t[i].r=r; if (l==r) return; int mid=(l+r)/2; build(i*2,l,mid); build(i*2+1,mid+1,r); } void add(int i,int pos,ll x){ int l=t[i].l,r=t[i].r,mid=(l+r)/2; if (l==r){t[i].ls+=x; t[i].rs+=x; t[i].sum+=x; t[i].ss+=x;return;} if (pos<=mid) add(i*2,pos,x); else add(i*2+1,pos,x); t[i].ls=max(t[i*2].ls,t[i*2].sum+t[i*2+1].ls); t[i].rs=max(t[i*2+1].rs,t[i*2+1].sum+t[i*2].rs); t[i].sum=t[i*2].sum+t[i*2+1].sum; t[i].ss=max(t[i*2].ss,t[i*2+1].ss); t[i].ss=max(t[i].ss,t[i*2].rs+t[i*2+1].ls); } int main(){ n=read(); m=read(); scanf("%lld%lld",&k,&d); build(1,1,n); rep(i,1,n) add(1,i,-k); rep(i,1,m){ int r; ll x; scanf("%d%lld",&r,&x); add(1,r,x); if (t[1].ss<=d*k) puts("TAK"); else puts("NIE"); } return 0; }