平衡二叉树SBT||线段树区间维护poj2892

来源:互联网 发布:朗伽病理软件 编辑:程序博客网 时间:2024/05/11 18:36

题意:有第三种操作:

D x表示毁掉村庄x;

Q x表示询问x在内的最大连续的村庄;

R表示重建最近被毁掉的村庄

思路:用一个栈存储被毁掉的村庄,以便修复。开一个访问数组,如果村庄被毁掉则标记,查询的时候直接输出0;

然后线段树维护连续的村庄。

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;const int maxn=50010;int n,m;bool vis[maxn];stack<int> s;struct IntervalTree{    int ls[maxn<<3],rs[maxn<<3];    void maintain(int o,int l,int r)    {        ls[o]=ls[o<<1],rs[o]=rs[o<<1|1];        int mid=(l+r)>>1;        if(ls[o]==mid-l+1)ls[o]+=ls[o<<1|1];        if(rs[o]==r-mid)rs[o]+=rs[o<<1];    }    void build(int o,int l,int r)    {        ls[o]=rs[o]=0;        if(l==r)        {            ls[o]=rs[o]=1;            return;        }        int mid=(l+r)>>1;        build(o<<1,l,mid);        build(o<<1|1,mid+1,r);        maintain(o,l,r);    }    void update(int o,int l,int r,int pos,int x)    {        if(l==r)        {            ls[o]+=x;            rs[o]+=x;            return ;        }        int mid=(l+r)>>1;        if(pos<=mid)update(o<<1,l,mid,pos,x);        else update(o<<1|1,mid+1,r,pos,x);        maintain(o,l,r);    }    int query(int o,int l,int r,int pos)//注意一下如何查询    {        int ans=0;        if(l==r)return 1;        int mid=(l+r)>>1;        if(pos<=mid)        {            if(pos>=mid-rs[o<<1]+1)return query(o<<1,l,mid,pos)+ls[o<<1|1];//如果在连续的那一段则要加上右孩子右面连续的一段;            else return query(o<<1,l,mid,pos);        }        else        {            if(pos<=mid+ls[o<<1|1])return query(o<<1|1,mid+1,r,pos)+rs[o<<1];            return query(o<<1|1,mid+1,r,pos);        }    }}tree;int main(){    //freopen("in.txt","r",stdin);    char op[5];    int x;    scanf("%d%d",&n,&m);    tree.build(1,1,n);    memset(vis,0,sizeof(vis));    while(m--)    {        scanf("%s",op);        if(op[0]=='D')        {            scanf("%d",&x);            vis[x]=1;            tree.update(1,1,n,x,-1);            s.push(x);        }        else if(op[0]=='Q')        {            scanf("%d",&x);            if(vis[x])printf("0\n");            else printf("%d\n",tree.query(1,1,n,x));        }        else        {            x=s.top();s.pop();            vis[x]=0;            tree.update(1,1,n,x,1);        }    }    return 0;}

现在用SBT重写一遍。

树中保存已经被摧毁的村庄,查询的时候只需要找到x的前驱跟后继,相减再减一就是区间长度

#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;const int maxn=50010;int vis[maxn];int N,M;stack<int> st;int root,tot;void init(){    while(!st.empty())st.pop();    memset(vis,0,sizeof(vis));    root=tot=0;}struct SBT{    int left,right,size,key;    void init(int val)    {        left=right=0;        key=val;        size=1;    }}tree[maxn];void left_rotate(int &x){    int y=tree[x].right;    tree[x].right=tree[y].left;    tree[y].left=x;    tree[y].size=tree[x].size;    tree[x].size=tree[tree[x].left].size+tree[tree[x].right].size+1;    x=y;}void right_rotate(int &x){    int y=tree[x].left;    tree[x].left=tree[y].right;    tree[y].right=x;    tree[y].size=tree[x].size;    tree[x].size=tree[tree[x].left].size+tree[tree[x].right].size+1;    x=y;}void maintain(int &x,int flag){    if(!flag)    {        if(tree[tree[tree[x].left].left].size>tree[tree[x].right].size)            right_rotate(x);        else if(tree[tree[tree[x].left].right].size>tree[tree[x].right].size)            left_rotate(tree[x].left),right_rotate(x);        else return;    }    else    {        if(tree[tree[tree[x].right].right].size>tree[tree[x].left].size)            left_rotate(x);        else if(tree[tree[tree[x].right].left].size>tree[tree[x].left].size)            right_rotate(tree[x].right),left_rotate(x);        else return;    }    maintain(tree[x].left,0);    maintain(tree[x].right,1);    maintain(x,0);    maintain(x,1);}//插入值为key的节点void insert(int &x,int key){    if(!x)    {        x=++tot;        tree[x].init(key);    }    else    {        tree[x].size++;        if(key<tree[x].key)insert(tree[x].left,key);        else insert(tree[x].right,key);        maintain(x,key>=tree[x].key);    }}int del(int &x,int key){    if(!x)return 0;    tree[x].size--;    if(key==tree[x].key||(key<tree[x].key&&tree[x].left==0)||       (key>tree[x].key&&tree[x].right==0))    {        if(tree[x].left&&tree[x].right)        {            int p=del(tree[x].left,key+1);            tree[x].key=tree[p].key;            return p;        }        else        {            int p=x;            x=tree[x].left+tree[x].right;            return p;        }    }    else        return del(key<tree[x].key?tree[x].left:tree[x].right,key);}//返回值v的前驱的值,如果没有前驱返回v本身int Pred(int t,int v){    if(!t)return v;    if(v<=tree[t].key)return Pred(tree[t].left,v);    else    {        int tmp=Pred(tree[t].right,v);        return v==tmp?tree[t].key:tmp;    }}//返回值v的后继的值,如果没有后继返回v本身int Succ(int t,int v){    if(!t)return v;    if(v>=tree[t].key)return Succ(tree[t].right,v);    else    {        int tmp=Succ(tree[t].left,v);        return v==tmp?tree[t].key:tmp;    }}int main(){    char op[5];    int x;    while(scanf("%d%d",&N,&M)!=EOF)    {        init();        while(M--)        {            scanf("%s",op);            if(op[0]=='D')            {                scanf("%d",&x);                //if(vis[x])continue;                vis[x]++;                st.push(x);                insert(root,x);            }            else if(op[0]=='R')            {                if(!st.empty())                {                    del(root,st.top());                    vis[st.top()]--;                    if(vis[st.top()]<=0)st.pop();                }            }            else            {                scanf("%d",&x);                if(vis[x])printf("0\n");                else                {                    int r=Succ(root,x);                    if(r==x)r=N+1;                    int l=Pred(root,x);                    if(l==x)l=0;                    printf("%d\n",r-l-1);                }            }        }    }    return 0;}


0 0