这题对于每个节点有 3个 附加信息 :
1.以左端点为首的最长连续空闲
2.以右端点为首的(向左数)最长空闲
3.该区间内总最长空闲
关键在 查找最靠左的线段上 如果 第一个节点也就是最长区间的 max<所需长度 输出0
然后 先考虑左边 再考虑左边接右边 最后考虑右边
#include <iostream> #include <string.h> #define Max(a,b) (a)>(b)?(a):(b) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; const int MAXN=50005; struct segtree{ int l,r,max; int len; int cov; }seg[MAXN<<2]; void pushdown(int rt) { if(seg[rt].cov!=-1){ seg[rt<<1].cov = seg[rt<<1|1].cov = seg[rt].cov; if(seg[rt].cov) seg[rt<<1].l=seg[rt<<1|1].l=seg[rt<<1].r=seg[rt<<1|1].r=seg[rt<<1].max=seg[rt<<1|1].max=0; else{ seg[rt<<1].l=seg[rt<<1].r=seg[rt<<1].len; seg[rt<<1|1].l=seg[rt<<1|1].r=seg[rt<<1|1].len; } seg[rt].cov=-1; } } void pushup(int rt) { seg[rt].l=seg[rt<<1].l; seg[rt].r=seg[rt<<1|1].r; if(seg[rt].l==seg[rt<<1].len) seg[rt].l+=seg[rt<<1|1].l; if(seg[rt].r==seg[rt<<1|1].len) seg[rt].r+=seg[rt<<1].r; seg[rt].max=Max(Max(seg[rt<<1].max,seg[rt<<1|1].max),seg[rt<<1].r+seg[rt<<1|1].l); } void build(int l,int r,int rt) { seg[rt].l=seg[rt].r=seg[rt].max=seg[rt].len=r-l+1; seg[rt].cov=-1; if(l==r) { return; } int m= r+l >>1; build(lson); build(rson); } void update(int val,int a,int b,int l,int r,int rt) { if(a<=l && b>=r){ if(val) seg[rt].l=seg[rt].r=seg[rt].max=0; else seg[rt].l=seg[rt].r=seg[rt].max=seg[rt].len; seg[rt].cov=val; return; } int m=(r+l)>>1; pushdown(rt); if(a<=m) update(val,a,b,lson); if(b>m) update(val,a,b,rson); pushup(rt); } int query(int num,int l,int r,int rt) { if(l==r) return l; int ret,m = r+l >>1; pushdown(rt); if(seg[rt<<1].max>=num) ret =query(num,lson); else if(seg[rt<<1].r+seg[rt<<1|1].l>=num) ret = m-seg[rt<<1].r+1; else ret= query(num,rson); pushup(rt); return ret; } int main() { int n,m,k,x,y; while(cin>>n>>m) { build(1,n,1); while(m--) { cin>>k; if(k==1) { cin>>x; if(seg[1].max<x) cout<<"0"<<endl; else { int tp = query(x,1,n,1); cout<<tp<<endl; update(1,tp,tp+x-1,1,n,1); } } else { cin>>x>>y; update(0,x,x+y-1,1,n,1); } } } return 0; }