【题解】Luogu P1503 鬼子进村

平衡树好题

原题传送门

这道题要用Splay,我博客里有对Splay的详细介绍

这道题思维有点难,要把被摧毁的节点插入平衡树,而不是把没有摧毁的节点插入

先把0和n+1插入平衡树,作为边界

操作1:摧毁节点,把该点插入平衡树

操作2:修复最后一个被摧毁节点的位置的可以用栈来求出,并把该点位置从平衡树中删除

操作三:搞一个vis数组,记录是否被摧毁,如果被摧毁了,直接输出0,没被摧毁的话,输出该点后继的位置-该点前驱的位置-1,这应该也很好理解qaq

剩下就没什么问题了(除了代码有点长)

#pragma GCC optimize("O3")
#include <bits/stdc++.h>
#define root tree[0].ch[1]
#define inf 1000000005
using namespace std;
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘)x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar(‘0‘);if(x<0)x=-x,putchar(‘-‘);
    static int sta[36];int cnt=0;
    while(x)sta[cnt++]=x%10,x/=10;
    while(cnt)putchar(sta[--cnt]+48);
}
inline int Min(register int a,register int b)
{
    return a<b?a:b;
}
inline int Max(register int a,register int b)
{
    return a>b?a:b;
}
struct Splay{
    int fa,ch[2],v,sum,rec;
}tree[50005];
int tot=0;
inline bool findd(register int x)
{
    return x==tree[tree[x].fa].ch[0]?0:1;
}
inline void connect(register int x,register int fa,register int son)
{
    tree[x].fa=fa;
    tree[fa].ch[son]=x;
}
inline void update(register int x)
{
    tree[x].sum=tree[tree[x].ch[0]].sum+tree[tree[x].ch[1]].sum+tree[x].rec;
}
inline void rotate(register int x)
{
    int Y=tree[x].fa;
    int R=tree[Y].fa;
    int Yson=findd(x);
    int Rson=findd(Y);
    int B=tree[x].ch[Yson^1];
    connect(B,Y,Yson);
    connect(Y,x,Yson^1);
    connect(x,R,Rson);
    update(Y),update(x);
}
inline void splay(register int x,register int to)
{
    to=tree[to].fa;
    while(tree[x].fa!=to)
    {
        int y=tree[x].fa;
        if(tree[y].fa==to)
            rotate(x);
        else if(findd(x)==findd(y))
            rotate(y),rotate(x);
        else
            rotate(x),rotate(x);
    }
}
inline int newpoint(register int v,register int fa)
{
    tree[++tot].v=v;
    tree[tot].fa=fa;
    tree[tot].sum=tree[tot].rec=1;
    return tot;
}
inline void Insert(register int x)
{
    int now=root;
    if(root==0)
    {
        newpoint(x,0);
        root=tot;
    }
    else
    {
        while(19260817)
        {
            ++tree[now].sum;
            if(x==tree[now].v)
            {
                ++tree[now].rec;
                splay(now,root);
                return;
            }
            int nxt=x<tree[now].v?0:1;
            if(!tree[now].ch[nxt])
            {
                int p=newpoint(x,now);
                tree[now].ch[nxt]=p;
                splay(p,root);
                return;
            }
            now=tree[now].ch[nxt];
        }
    }
}
inline int find(register int x)
{
    int now=root;
    while(19260817)
    {
        if(x==tree[now].v)
        {
            splay(now,root);
            return now;
        }
        int nxt=x<tree[now].v?0:1;
        if(!tree[now].ch[nxt])
            return 0;
        now=tree[now].ch[nxt];
    }
}
inline void delet(register int x)
{
    int pos=find(x);
    if(!pos)
        return;
    if(tree[pos].rec>1)
    {
        --tree[pos].rec;
        --tree[pos].sum;
    }
    else
    {
        if(!tree[pos].ch[0]&&!tree[pos].ch[1])
            root=0;
        else if(!tree[pos].ch[0])
        {
            root=tree[pos].ch[1];
            tree[root].fa=0;
        }
        else
        {
            int left=tree[pos].ch[0];
            while(tree[left].ch[1])
                left=tree[left].ch[1];
            splay(left,tree[pos].ch[0]);
            connect(tree[pos].ch[1],left,1);
            connect(left,0,1);
            update(left);
        }
    }
}
inline int lower(register int v)
{
    int now=root,ans=-inf;
    while(now)
    {
        if(tree[now].v<v&&tree[now].v>ans)
            ans=tree[now].v;
        if(tree[now].v>v)
            now=tree[now].ch[0];
        else
            now=tree[now].ch[1];
    }
    return ans;
}
inline int upper(register int v)
{
    int now=root,ans=inf;
    while(now)
    {
        if(tree[now].v>v&&tree[now].v<ans)
            ans=tree[now].v;
        if(tree[now].v>v)
            now=tree[now].ch[0];
        else
            now=tree[now].ch[1];
    }
    return ans;
}
bool vis[50005];
int stac[50005],top=-1;
int main()
{
    memset(vis,false,sizeof(vis));
    int n=read(),m=read();
    Insert(0);
    Insert(n+1);
    while(m--)
    {
        char ch=getchar();
        while(ch!=‘D‘&&ch!=‘R‘&&ch!=‘Q‘)
            ch=getchar();
        if(ch==‘D‘)
        {
            int x=read();
            vis[x]=true;
            stac[++top]=x;
            Insert(x);
        }
        else if(ch==‘R‘)
        {
            vis[stac[top]]=false;
            delet(stac[top--]);
        }
        else
        {
            int x=read();
            if(vis[x])
                puts("0");
            else
            {
                write(upper(x)-lower(x)-1);
                printf("\n");
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/9960345.html

时间: 2024-10-10 15:01:28

【题解】Luogu P1503 鬼子进村的相关文章

LUOGU P1503 鬼子进村

传送门 解题思路 平衡树,支持插入,删除,找前驱后继,set水过. #include<iostream> #include<cstdio> #include<cstring> #include<set> using namespace std; const int MAXN = 50005; inline int rd(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) {f=ch=='-'?0:1;c

洛谷 P1503 鬼子进村

P1503 鬼子进村 题目背景 小卡正在新家的客厅中看电视.电视里正在播放放了千八百次依旧重播的<亮剑>,剧中李云龙带领的独立团在一个县城遇到了一个鬼子小队,于是独立团与鬼子展开游击战. 题目描述 描述 县城里有n个用地道相连的房子,第i个只与第i-1和第i+1个相连.这是有m个消息依次传来 1.消息为D x:鬼子将x号房子摧毁了,地道被堵上. 2.消息为R :村民们将鬼子上一个摧毁的房子修复了. 3.消息为Q x:有一名士兵被围堵在x号房子中. 李云龙收到信息很紧张,他想知道每一个被围堵的士

洛谷—— P1503 鬼子进村

https://www.luogu.org/problemnew/show/P1503 题目背景 小卡正在新家的客厅中看电视.电视里正在播放放了千八百次依旧重播的<亮剑>,剧中李云龙带领的独立团在一个县城遇到了一个鬼子小队,于是独立团与鬼子展开游击战. 题目描述 描述 县城里有n个用地道相连的房子,第i个只与第i-1和第i+1个相连.这是有m个消息依次传来 1.消息为D x:鬼子将x号房子摧毁了,地道被堵上. 2.消息为R :村民们将鬼子上一个摧毁的房子修复了. 3.消息为Q x:有一名士兵被

洛谷 P1503鬼子进村

题目背景 小卡正在新家的客厅中看电视.电视里正在播放放了千八百次依旧重播的<亮剑>,剧中李云龙带领的独立团在一个县城遇到了一个鬼子小队,于是独立团与鬼子展开游击战. 题目描述 描述 县城里有n个用地道相连的房子,第i个只与第i-1和第i+1个相连.这是有m个消息依次传来 1.消息为D x:鬼子将x号房子摧毁了,地道被堵上. 2.消息为R :村民们将鬼子上一个摧毁的房子修复了. 3.消息为Q x:有一名士兵被围堵在x号房子中. 李云龙收到信息很紧张,他想知道每一个被围堵的士兵能够到达的房子有几个

P1503 鬼子进村

题目背景 小卡正在新家的客厅中看电视.电视里正在播放放了千八百次依旧重播的<亮剑>,剧中李云龙带领的独立团在一个县城遇到了一个鬼子小队,于是独立团与鬼子展开游击战. 题目描述 描述 县城里有n个用地道相连的房子,第i个只与第i-1和第i+1个相连.这是有m个消息依次传来 1.消息为D x:鬼子将x号房子摧毁了,地道被堵上. 2.消息为R :村民们将鬼子上一个摧毁的房子修复了. 3.消息为Q x:有一名士兵被围堵在x号房子中. 李云龙收到信息很紧张,他想知道每一个被围堵的士兵能够到达的房子有几个

题解 luogu P1850 【换教室】

题解 luogu P1850 [换教室] 时间:2019.8.6 一晚上(约 3.5h 写完) 题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有 \(2n\) 节课程安排在 \(n\) 个时间段上.在第 \(i\)(\(1 \leq i \leq n\))个时间段上,两节内容相同的课程同时在不同的地点进行,其中,牛牛预先被安排在教室 \(c_i\) 上课,而另一节课程在教室 \(d_i\) 进行. 在不提交任何申请的情况下,学生们需要

题解 luogu P5021 【赛道修建】

题解 luogu P5021 [赛道修建] 时间:2019.8.9 20:40 时间:2019.8.12 题目描述 C 城将要举办一系列的赛车比赛.在比赛前,需要在城内修建 \(m\) 条赛道. C 城一共有 \(n\) 个路口,这些路口编号为 \(1,2,\dots,n\),有 \(n-1\) 条适合于修建赛道的双向通行的道路,每条道路连接着两个路口.其中,第 \(i\) 条道路连接的两个路口编号为 \(a_i\) 和 \(b_i\),该道路的长度为 \(l_i\).借助这 \(n-1\) 条

题解 Luogu P2499: [SDOI2012]象棋

关于这道题, 我们可以发现移动顺序不会改变答案, 具体来说, 我们有以下引理成立: 对于一个移动过程中的任意一个移动, 若其到达的位置上有一个棋子, 则该方案要么不能将所有棋子移动到最终位置, 要么可以通过改变顺序使这一次移动合法 证明: 考虑到达位置上的那个棋子, 如果它没有到达最终位置, 则我们考虑将该棋子移至下一步, 如果下一步还有没有到达最终位置的棋子, 则也移动它 否则直接调换这两个棋子的移动顺序即可 好的我们去除了题目中的要求: 「移动过程中不能出现多颗棋子同时在某一格的情况」, 接

鬼子进村(洛谷 1503)

题目背景 小卡正在新家的客厅中看电视.电视里正在播放放了千八百次依旧重播的<亮剑>,剧中李云龙带领的独立团在一个县城遇到了一个鬼子小队,于是独立团与鬼子展开游击战. 题目描述 描述 县城里有n个用地道相连的房子,第i个只与第i-1和第i+1个相连.这是有m个消息依次传来 1.消息为D x:鬼子将x号房子摧毁了,地道被堵上. 2.消息为R :村民们将鬼子上一个摧毁的房子修复了. 3.消息为Q x:有一名士兵被围堵在x号房子中. 李云龙收到信息很紧张,他想知道每一个被围堵的士兵能够到达的房子有几个