题意:
有一个线段,从1到n,下面m个操作,操作分两个类型,以1开头的是查询操作,以2开头的是更新操作
1 w 表示在总区间内查询一个长度为w的可用区间并且要最靠左,能找到的话返回这个区间的左端点并占用了这个区间,找不到返回0
2 a len , 表示从单位a开始,清除一段长度为len的区间(将其变为可用,不被占用),不需要输出。
思路:
这是第一次遇到线段树区间合并的题目,写下感悟,还是对线段的更新和查询工作,但是查询的对象的性质已经不像单点那样,查询的是某个线段的最大可用区间是多少,还要一并查询出最大可用区间最左端的位置,显然不能直接记录最左边的位置,因为父亲和儿子没有递推关系,所以要开其他的线段树记录其他的量,每次查询最起码要在O(1)的时间内算出最大可用区间的最左端位置。
而且也不能光记录最大可用间的长度是多少,因为这样父亲和儿子也构不成递推关系。所以要记录开其他的线段树,这是这类区间合并的共同问题,下面直接说解法方法:
可以开三棵线段树,一个记录此区间的最大可用区间的长度,一个记录此区间从左边开始的可用空间的长度,还有一个记录此区间从右边开始的可用空间的长度。记录这三个量可以互相递推pushup掉三棵线段树上所有的父亲。具体的递推关系可以见代码,但这里必须知道为什么可以递推,因为记录了整个区间从左右端开始延伸的可用空间的长度,递归处理左右儿子,就等价与记录了整个区间上哪些位置可用,哪些位置不可用,就把第一课线段树记录的最大可用空间细节化了,接下来可操作性任意强。
//2720 KB 1063 ms #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define M 50005 #define root 1,n,1 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; int mmax[M<<2],lmax[M<<2],rmax[M<<2]; //mmax记录整个区间的最大连续空位,lmax记录了这个区间从左边开始的连续空位,rmax记录了这个区间从右边开始的连续空位 int col[M<<2]; //lazy tag int n,m; void build(int l,int r,int rt) { col[rt]=-1; mmax[rt]=lmax[rt]=rmax[rt]=r-l+1; if(l==r){ return; } int m=(l+r)>>1; build(lson); build(rson); } void pushup(int rt,int m) { lmax[rt]=lmax[rt<<1]; rmax[rt]=rmax[rt<<1|1]; if(lmax[rt]==m-(m>>1)) lmax[rt]+=lmax[rt<<1|1]; if(rmax[rt]==(m>>1)) rmax[rt]+=rmax[rt<<1]; mmax[rt]=max(rmax[rt<<1]+lmax[rt<<1|1],max(mmax[rt<<1],mmax[rt<<1|1]) ); //mmax[rt]可能是横跨了左右儿子,也可能是左右儿子中的mmax } void pushdown(int rt,int m) { if(col[rt]==-1) return; col[rt<<1]=col[rt<<1|1]=col[rt]; mmax[rt<<1]=lmax[rt<<1]=rmax[rt<<1] = col[rt]? 0 :m-(m>>1); mmax[rt<<1|1] = lmax[rt<<1|1] =rmax[rt<<1|1]=col[rt]? 0:(m>>1); col[rt]=-1; } int query(int x,int l,int r,int rt) { if(mmax[rt]<x){ //也就是mmax[1]<x只有这一种情况 return 0; } if(l==r) return l; //这种情况可能发生x=1的时候 pushdown(rt,r-l+1); int m=(l+r)>>1; if(mmax[rt<<1]>=x) return query(x,lson); if(rmax[rt<<1]+lmax[rt<<1|1]>=x) return m-rmax[rt<<1]+1; //直接找到答案 if(mmax[rt<<1|1]>=x) return query(x,rson); } void update(int L,int R,int c,int l,int r,int rt) { if(L<=l&&r<=R){ col[rt]=c; mmax[rt]=lmax[rt]=rmax[rt]= c? 0:(r-l+1); return; } pushdown(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(L,R,c,lson); if(R>m) update(L,R,c,rson); pushup(rt,r-l+1); } int main() { scanf("%d%d",&n,&m); build(root); while(m--){ int op; scanf("%d",&op); if(op==1){ int x; scanf("%d",&x); int ans=query(x,root); printf("%d\n",ans); if(ans) update(ans,ans+x-1,1,root); } else { int a,b; scanf("%d%d",&a,&b); update(a,a+b-1,0,root); } } return 0; }
时间: 2024-10-23 04:25:17