第一道这样的题目,转自这里点击打开链接
只是照抄了一下,然后体味了一下大神的思维,以及自己的不慎
#include<cstdio> #include<iostream> #include<cstring> #define left l,m,x<<1 #define right m+1,r,x<<1|1 #define LMT 50005 using namespace std; //一般都是左子树多一点 int msum[LMT<<2],rsum[LMT<<2],lsum[LMT<<2],cover[LMT<<2]; //msum指的是在某个区间“内”的最大空白 int max(int a,int b) { return a>b?a:b; } void build(int l,int r,int x) { msum[x]=lsum[x]=rsum[x]=r-l+1; if(l==r)return; int m=(l+r)>>1; build(left);build(right); } void cut(int x,int have) { if(cover[x]!=-1) { cover[x<<1]=cover[x<<1|1]=cover[x]; msum[x<<1]=lsum[x<<1]=rsum[x<<1]=cover[x]?0:have-(have>>1); msum[x<<1|1]=lsum[x<<1|1]=rsum[x<<1|1]=cover[x]?0:have>>1; cover[x]=-1; } } /*** 这个函数是子树重新覆盖后,记录对父节点的影响的 ***/ void refill(int x,int have) { lsum[x]=lsum[x<<1]; rsum[x]=rsum[x<<1|1]; if(lsum[x]==have-(have>>1))lsum[x]+=lsum[x<<1|1]; if(rsum[x]==have>>1)rsum[x]+=rsum[x<<1];//别搞错了.. msum[x]=max(rsum[x<<1]+lsum[x<<1|1],max(msum[x<<1],msum[x<<1|1])); } void update(int L,int R,int c,int l,int r,int x) { if(L<=l&&r<=R) { msum[x]=rsum[x]=lsum[x]=c?0:r-l+1; cover[x]=c; return; } cut(x,r-l+1); int m=(l+r)>>1; if(L<=m)update(L,R,c,left); if(R>m)update(L,R,c,right); refill(x,r-l+1); } int query(int need,int l,int r,int x) { if(l==r)return l; cut(x,r-l+1); int m=(l+r)>>1; if(msum[x<<1]>=need)return query(need,left); if(rsum[x<<1]+lsum[x<<1|1]>=need)return m-rsum[x<<1]+1; return query(need,right); } int main() { int n,m; scanf("%d%d",&n,&m); build(1,n,1); memset(cover,-1,sizeof cover); while(m--) { int op,a,b,ans; scanf("%d",&op); if(op==1) { scanf("%d",&a); if(msum[1]<a)printf("0\n"); else { ans=query(a,1,n,1); printf("%d\n",ans); update(ans,ans+a-1,1,1,n,1); } } else { scanf("%d%d",&a,&b); update(a,a+b-1,0,1,n,1); } } return 0; }