洛谷 P1503 鬼子进村

洛谷 P1503 鬼子进村

Description

  • 描述 县城里有n个用地道相连的房子,第i个只与第i-1和第i+1个相连。这是有m个消息依次传来

    1、消息为D x:鬼子将x号房子摧毁了,地道被堵上。

    2、消息为R :村民们将鬼子上一个摧毁的房子修复了。

    3、消息为Q x:有一名士兵被围堵在x号房子中。

    李云龙收到信息很紧张,他想知道每一个被围堵的士兵能够到达的房子有几个。

Input

  • 第一行2个整数n,m(n,m<=50000)。

    接下来m行,有如题目所说的三种信息共m条。

Output

  • 对于每一个被围堵的士兵,输出该士兵能够到达的房子数。

Sample Input

7 9
D 3
D 6
D 5
Q 4
Q 5
R
Q 4
R
Q 4

Sample Output

1

0

2

4

题解:

  • 平衡树。
  • 终于脱离了模版题的范畴。这题如果想到用平衡树思路就很容易想到了。用Treap维护被摧毁的房子位置,D操作就插入位置,Q操作(设给的当前位置为x)的答案就是(x的后继 - x的前继 - 1)。R操作弄一个栈依题意模拟即可。
  • 还是一句话,平衡树的前继后继函数要巧用!
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <stack>
#define N 50005
using namespace std;

struct T {int l, r, val, dat;} t[N];
int n, m, root, tot;
stack<int> stk;

int read()
{
    int x = 0; char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
    return x;
}

int New(int val)
{
    t[++tot].val = val;
    t[tot].dat = rand();
    return tot;
}

void zig(int &y)
{
    int x = t[y].l;
    t[y].l = t[x].r, t[x].r = y, y = x;
}

void zag(int &x)
{
    int y = t[x].r;
    t[x].r = t[y].l, t[y].l = x, x = y;
}

void insert(int &p, int val)
{
    if(!p) {p = New(val); return;}
    if(val == t[p].val) return;
    if(val < t[p].val)
    {
        insert(t[p].l, val);
        if(t[t[p].l].dat > t[p].dat) zig(p);
    }
    else
    {
        insert(t[p].r, val);
        if(t[t[p].r].dat > t[p].dat) zag(p);
    }
}

void erase(int &p, int val)
{
    if(!p) return;
    if(val == t[p].val)
    {
        if(t[p].l || t[p].r)
        {
            if(!t[p].r || t[t[p].l].dat > t[p].dat) zig(p), erase(t[p].r, val);
            else zag(p), erase(t[p].l, val);
        }
        else p = 0;
        return;
    }
    val < t[p].val ? erase(t[p].l, val) : erase(t[p].r, val);
}

int preNext(int op, int val)
{
    int ans = op == 0 ? 2 : 1, p = root;
    while(p)
    {
        if(val == t[p].val)
        {
            if(!op && t[p].l)
            {
                p = t[p].l;
                while(t[p].r) p = t[p].r;
                ans = p;  break;
            }
            else if(!op) break;
            if(op && t[p].r)
            {
                p = t[p].r;
                while(t[p].l) p = t[p].l;
                ans = p; break;
            }
            else if(op) break;
        }
        if(!op && t[p].val < val && t[p].val > t[ans].val) ans = p;
        if(op && t[p].val > val && t[p].val < t[ans].val) ans = p;
        p = val < t[p].val ? t[p].l : t[p].r;
    }
    return t[ans].val;
}

bool find(int p, int val)
{
    if(!p) return 0;
    if(val == t[p].val) return 1;
    if(val < t[p].val) return find(t[p].l, val);
    else return find(t[p].r, val);
}

int main()
{
    cin >> n >> m;
    New(n + 1), New(0), root = 1, t[1].l = 2;
    for(int i = 1; i <= m; i++)
    {
        char c[2]; scanf("%s", c);
        if(c[0] == 'D')
        {
            int x = read();
            insert(root, x);
            stk.push(x);
        }
        else if(c[0] == 'R')
        {
            erase(root, stk.top());
            stk.pop();
        }
        else if(c[0] == 'Q')
        {
            int x = read();
            if(find(root, x)) printf("0\n");
            else printf("%d\n", preNext(1, x) - preNext(0, x) - 1);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/BigYellowDog/p/11324588.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值