hdu-1540(线段树+最大连续区间)

/*
在区间中,有三种操作,
Q x 查询包含x的最长连续区间
D x 将x点毁掉即x点左右不再连续
R   修复上一次毁坏的点
思路:记录每个区间的左右端的连续区间长度,
   x若在左端点连续区间,则该区间只可能是其父亲的右孩子,
   因为如果是左孩子,则访问其父区间的时候,父区间的左连续区间便已包含x。
   所以直接将该右孩子区间的左连续区间加上其兄弟区间的右连续区间即是最终结果。
   
   毁坏的点按顺序保存栈里,注意!可能同一个点毁坏多次,但仍需入站!栈空无需修复。
*/
#include 
#include
using namespace std;
#define N 50010
struct node
{
    int l,r;
    int ln,rn;//记录该区间左右连续区间的长度
    int len;//该区间的长度
}tree[N*4];
void build(int l,int r,int root)
{
    tree[root].l=l;
    tree[root].r=r;
    tree[root].ln=tree[root].rn=r-l+1;//初始化左右连续区间都为区间长度
    tree[root].len=r-l+1;
    if(l==r) {

            return;
    }
    int mid=(l+r)>>1;
    build(l,mid,root*2);
    build(mid+1,r,root*2+1);
}
int query(int x,int root)
{
    if(root==1){   //树根区间没兄弟,直接输出连续区间
        if(tree[root].ln){
        if((tree[root].l+tree[root].ln-1)>=x) return tree[root].ln;
    }
        if(tree[root].rn){
        if((tree[root].r-tree[root].rn+1)<=x) return tree[root].rn;
    }
    }
    if(tree[root].ln){
        if((tree[root].l+tree[root].ln-1)>=x) return tree[root].ln+tree[root-1].rn;
    }
     if(tree[root].rn){
        if((tree[root].r-tree[root].rn+1)<=x) return tree[root].rn+tree[root+1].ln;
    }
    if(tree[root].l==tree[root].r) return 0;
    int mid=(tree[root].l+tree[root].r)>>1;
    if(mid>=x) return query(x,root*2);
    else return query(x,root*2+1);
}
void update(int x,int root,int b)//b=0为毁坏操作,1修复
{
    if(tree[root].l==tree[root].r){
         tree[root].ln=tree[root].rn=b;
        return;
    }
    int mid=(tree[root].l+tree[root].r)>>1;
    if(mid>=x) update(x,root*2,b);
    else update(x,root*2+1,b);
    if(tree[root*2].ln+tree[root*2+1].rn==tree[root].len)
        tree[root].ln=tree[root].rn=tree[root].len;
    else{
        if(tree[root*2].ln==tree[root*2].len) tree[root].ln=tree[root*2].len+tree[root*2+1].ln;
        else tree[root].ln=tree[root*2].ln;
        if(tree[root*2+1].rn==tree[root*2+1].len) tree[root].rn=tree[root*2+1].len+tree[root*2].rn;
        else tree[root].rn=tree[root*2+1].rn;
    }
}
int main()
{
    int n,m,x;
    char c;
    int que[N];
    int f=0;
    while(~scanf("%d%d",&n,&m)){
            f=0;
    build(1,n,1);
    for(int t=1;t<=m;t++)
    {
        getchar();
        scanf("%c",&c);
        if(c=='D') {
            scanf("%d",&x);
            que[++f]=x;
            update(x,1,0);
        }
        else if(c=='Q'){
            scanf("%d",&x);
            printf("%d\n",query(x,1));
        }
        else{
                if(f==0) continue;
                int k=que[f--];
              update(k,1,1);
        }
    }
    }
    return 0;
}


你可能感兴趣的:(线段树)