POJ 3667
维护左连续,右连续区间最大值,同时维护区间内最大的连续区间值。同时是使用标记法完成。很强大。
注意出现的状态-1,很巧妙,代表该结点不能再下传了,即不符合下传条件。
#include <cstdio> #include <cstring> #include <cctype> #include <algorithm> using namespace std; const int maxn = 55555; int lsum[maxn<<2] , rsum[maxn<<2] , msum[maxn<<2]; int cover[maxn<<2]; void build(int rt,int l,int r){ cover[rt]=-1; lsum[rt]=rsum[rt]=msum[rt]=r-l+1; if(l==r) return; int m=(l+r)>>1; build(rt<<1,l,m); build(rt<<1|1,m+1,r); } void PushDown(int rt,int m){ if(cover[rt]!=-1){ cover[rt<<1]=cover[rt<<1|1]=cover[rt]; lsum[rt<<1]=rsum[rt<<1]=msum[rt<<1]=cover[rt]?0:(m-(m>>1)); lsum[rt<<1|1]=rsum[rt<<1|1]=msum[rt<<1|1]=cover[rt]?0:(m>>1); cover[rt]=-1; } } void PushUp(int rt,int m){ lsum[rt]=lsum[rt<<1]; rsum[rt]=rsum[rt<<1|1]; if(lsum[rt]==(m-(m>>1))) lsum[rt]+=lsum[rt<<1|1]; if(rsum[rt]==(m>>1)) rsum[rt]+=rsum[rt<<1]; msum[rt]=max(lsum[rt<<1|1]+rsum[rt<<1],max(msum[rt<<1],msum[rt<<1|1])); msum[rt]=max(msum[rt],lsum[rt]); msum[rt]=max(msum[rt],rsum[rt]); } int query(int rt,int l,int r,int w){ if(l==r) return l; PushDown(rt,r-l+1); int m=(l+r)>>1; if(msum[rt<<1]>=w) return query(rt<<1,l,m,w); else if(rsum[rt<<1]+lsum[rt<<1|1]>=w) return m-rsum[rt<<1]+1; return query(rt<<1|1,m+1,r,w); } void update(int rt,int L,int R,int l,int r,int c){ if(L<=l&&r<=R){ cover[rt]=c; lsum[rt]=rsum[rt]=msum[rt]=c?0:r-l+1; return ; } PushDown(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(rt<<1,L,R,l,m,c); if(m<R) update(rt<<1|1,L,R,m+1,r,c); PushUp(rt,r-l+1); } int main(){ int n,m,op,a,b; while(scanf("%d%d",&n,&m)!=EOF){ build(1,1,n); for(int i=1;i<=m;i++){ scanf("%d",&op); if(op==1){ scanf("%d",&a); if(msum[1]>=a){ int p=query(1,1,n,a); update(1,p,p+a-1,1,n,1); printf("%d\n",p); } else printf("0\n"); } else{ scanf("%d%d",&a,&b); update(1,a,a+b-1,1,n,0); } } } return 0; }