hdu 1540(线段树区间合并)
题目链接:传送门
参考文章:传送门
题意:n个数字初始连在一条线上,有三种操作,
D x表示x号被摧毁;
R 表示恢复剩下的通路
Q表示查询标号为x所在的串的最长长度。
思路:线段树的区间合并。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 50500; struct Node{ int l,r; int ls,rs,ms; }cur[maxn<<2]; int ss[maxn],m,n; void build(int x,int l,int r) //初始化建树 { cur[x].l=l;cur[x].r=r; cur[x].ls=cur[x].rs=cur[x].ms=r-l+1; if(l==r) return ; int mid=(l+r)>>1; build(x*2,l,mid); build(x*2+1,mid+1,r); } int MAX(int x,int y) { return x>y?x:y; } void update(int x,int pos,int fg) { if(cur[x].l==cur[x].r) { if(fg==0) cur[x].ls=cur[x].rs=cur[x].ms=0; //删除 else cur[x].ls=cur[x].rs=cur[x].ms=1; //更新 return ; } int mid=(cur[x].l+cur[x].r)>>1; if(pos<=mid) update(x*2,pos,fg); else update(x*2+1,pos,fg); //pushup操作,更新左子区间,右子区间的最长长度 cur[x].ls=cur[x*2].ls; cur[x].rs=cur[x*2+1].rs; cur[x].ms=MAX(MAX(cur[x*2].ms,cur[x*2+1].ms),cur[x*2].rs+cur[x*2+1].ls); if(cur[x*2].ls==cur[x*2].r-cur[x*2].l+1) cur[x].ls+=cur[x*2+1].ls; //如果区间的左子树的左区间已经满了,就加上右子树的左子区间 if(cur[x*2+1].rs==cur[x*2+1].r-cur[x*2+1].l+1) cur[x].rs+=cur[x*2].rs; // 如果右子树的右子区间已经满了,就加上左子树的右子区间 } int query(int x,int pos) { if(cur[x].ms==0||cur[x].l==cur[x].r||cur[x].ms==cur[x].r-cur[x].l+1) return cur[x].ms; int mid=(cur[x].l+cur[x].r)>>1; if(pos<=mid) { if(pos>=cur[x*2].r-cur[x*2].rs+1) return query(x*2,pos)+query(x*2+1,mid+1);//如果在左子区间的右边界,就遍历两个区间 return query(x*2,pos); } else { if(pos<=cur[x*2+1].l+cur[x*2+1].ls-1) return query(x*2+1,pos)+query(x*2,mid); //如果在右子区间的左边界,就遍历两个区间 return query(x*2+1,pos); } } int main(void) { while(~scanf("%d%d",&n,&m)) { build(1,1,n); char op[2]; int x,top=0; while(m--) { scanf("%s",op); if(op[0]=='D') { scanf("%d",&x); ss[top++]=x; update(1,x,0); } else if(op[0]=='Q') { scanf("%d",&x); printf("%d\n",query(1,x)); } else if(op[0]=='R') { x=ss[--top]; update(1,x,1); } } } return 0; }