您的位置:首页 > 运维架构

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

2014-07-07 16:11 267 查看
题意:有第三种操作:

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: