hdu1540 poj2892 Tunnel Warfare 线段树端点更新 SBT

42 篇文章 0 订阅
37 篇文章 0 订阅

题目大意,给n个点表示n个村庄,一开始都是相连的,现在有3种操作:Q x,查询第与第x个村庄相连的村庄个数;D x,摧毁掉第x个村庄;R  恢复刚摧毁的村庄。

题目分析:每个点用2个状态表示,0表示被摧毁,1表示存在,因为有恢复操作,并且每次恢复上一个被摧毁的村庄,所以用一个栈存储所有被摧毁的村庄,每次R操作恢复栈顶村庄。这题关键是查询操作,如果查询的村庄x不存在,则没有村庄与之相连通,如果存在x村庄,那么从x往2边找连续的存在的村庄。如何找这个连续的存在的村庄。

自顶向下找,如果找到左边第一个不存在的村庄,找到右边第一个不存在的村庄,相减即可。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
using namespace std;
#define maxn 50005
#define lson rt<<1 , l , m
#define rson rt<<1|1 , m+1 , r
int tree[maxn<<2],leaf[maxn],n;
void build(int rt,int l,int r)
{
    if(l==r)
    {
        tree[rt]=1;
        leaf[l]=rt;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}

void update(int rt,int l,int r,int x,int val)
{
    if(l==r)
    {
        tree[rt]=val;
        return ;
    }
    int m=(l+r)>>1;
    if(x<=m)
        update(lson,x,val);
    else
        update(rson,x,val);
    if(tree[rt<<1]==(m-l+1)&&tree[rt<<1|1]==r-m)
        tree[rt]=r-l+1;
    else
        tree[rt]=0;
}
int query(int rt,int l,int r,int x,int dir)
{
    int m=(l+r)>>1;
    if(x<1||x>n)
    {
        return x;
    }
    if(tree[rt]==r-l+1)
    {
        if(dir)
        {
            return query(1,1,n,r+1,dir);
        }
        else
        {
            return query(1,1,n,l-1,dir);
        }
    }
    if(l==r)
    {
        return l;
    }
    if(x<=m)
        return query(lson,x,dir);
    else
        return query(rson,x,dir);
}
int main()
{
    
    char op[5];
    int m,a,b,c,x,y,z;
    while(~scanf("%d%d",&n,&m))
    {
        stack<int>st;
        build(1,1,n);
        for(int i=1;i<=m;i++)
        {
            scanf("%s",op);
            if(op[0]=='R')
            {
                int num=st.top();
                st.pop();
                update(1,1,n,num,1);
            }
            else
            {
                scanf("%d",&x);
                if(op[0]=='D')
                {
                    st.push(x);
                    update(1,1,n,x,0);
                }
                else
                {
                    int ans = tree[leaf[x]];
                    if(ans == 0)
                        printf("0\n");
                    else
                    {
                        ans=1;
                        if(x<n)
                        {
                            ans+=query(1,1,n,x+1,1)-x-1;
                        }
                        if(x>1)
                        {
                            ans+=x-query(1,1,n,x-1,0)-1;
                        }
                        printf("%d\n",ans);
                    }
                }
            }
        }
    }
    return 0;
}

SBT版,比poj多了一个坑点,就是同一个城市可以删多次,对于线段树无所谓,可对于SBT来说会造成多个相同值的插入。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <stack>
#include <algorithm>
using namespace std;
#define maxn 510000
int n,m,l,r,root,cnt,val[maxn],ls[maxn],rs[maxn],siz[maxn];
bool vis[maxn];
void rotate_r(int &x)
{
    int y=ls[x];
    siz[y]=siz[x];
    ls[x]=rs[y];
    rs[y]=x;
    siz[x]=siz[ls[x]]+siz[rs[x]]+1;
    x=y;
}
void rotate_l(int &x)
{
    int y=rs[x];
    siz[y]=siz[x];
    rs[x]=ls[y];
    ls[y]=x;
    siz[x]=siz[ls[x]]+siz[rs[x]]+1;
    x=y;
}
void maintain(int& x,int fg)
{
    if(!fg)
    {
        if(siz[ls[ls[x]]]>siz[rs[x]]) rotate_r(x);
        else if(siz[rs[ls[x]]]>siz[rs[x]]) rotate_l(ls[x]),rotate_r(x);
        else return ;
    }
    else
    {
        if(siz[rs[rs[x]]]>siz[ls[x]]) rotate_l(x);
        else if(siz[ls[rs[x]]]>siz[ls[x]]) rotate_r(rs[x]),rotate_l(x);
        else return ;
    }
    maintain(ls[x],0);maintain(rs[x],1);
    maintain(x,0);maintain(x,1);
}
void insert(int& x,int b)
{
    if(!x)
    {
        cnt++;
        x=cnt;
        ls[x]=rs[x]=0;
        siz[x]=1;
        val[x]=b;
    }
    else
    {
        siz[x]++;
        if(b>val[x]) insert(rs[x],b);
        else insert(ls[x],b);
        maintain(x,b>=val[x]);
    }
}
int delt(int& x,int b)
{
    siz[x]--;
    if(b==val[x]||(b<val[x]&&ls[x]==0)||(b>val[x]&&rs[x]==0))
    {
        int y=val[x];
        if(!ls[x]||!rs[x]) x=ls[x]+rs[x];
        else val[x]=delt(ls[x],b+1);
        return y;
    }
    else
    {
        if(b<val[x]) return delt(ls[x],b);
        else return delt(rs[x],b);
    }
}
int pred(int&x ,int y,int b)
{
    if(!x) return y;
    if(val[x]<b) return pred(rs[x],x,b);
    return pred(ls[x],y,b);
}
int succ(int&x ,int y,int b)
{
    if(!x) return y;
    if(val[x]>b) return succ(ls[x],x,b);
    return succ(rs[x],y,b);
}
void sbt()
{
    root=cnt=0;
    memset(ls,0,sizeof(ls));
    memset(rs,0,sizeof(rs));
    memset(siz,0,sizeof(siz));
    memset(vis,0,sizeof(vis));
    memset(val,0,sizeof(val));
    insert(root,0);
    insert(root,n+1);
    int op,a,b,f;
    char str[10];
    stack<int>st;
    for(int i=1;i<=m;i++)
    {
        scanf("%s",str);
        if(str[0]=='D')
        {
            scanf("%d",&b);
            if(!vis[b]) insert(root,b);
            st.push(b);
            vis[b]=true;
        }
        else if(str[0]=='Q')
        {
            scanf("%d",&b);
            if(vis[b])
            {
                printf("0\n");
                continue;
            }
            int f1=pred(root,0,b);
            int f2=succ(root,0,b);
            printf("%d\n",val[f2]-val[f1]-1);
        }
        else
        {
            delt(root,st.top());
            vis[st.top()]=false;
            st.pop();
        }
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        sbt();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值