HDU-1540线段树

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1540

题目大意:

一些村庄排成一排,编号1-N,只要中间没有被摧毁的村庄,两个村庄就算是连接在一起的,现在有三个操作
1.摧毁编号为X的村庄
2.询问与村庄X连接的村庄有几个
3.重建上一个被摧毁的村庄

思路

我们只要知道查询的村庄X,它的左边最近的一个被摧毁的村庄,和它右边最近的一个被摧毁的村庄,就可以知道与X相连的村庄个数
所以考虑使用线段树来维护区间内被摧毁的村庄的数量,查询时如果区间的断点数为0直接返回,否则进行递归,同时更新记录上述的两个座标,然后根据最后的座标分类讨论一下就是答案了
重建村庄弄个栈搞一搞就好了
题目的坑点有:
1.题目没说是多组,但其实是多组
2.村庄可以重复摧毁,但是重建只需一次即可

AC代码

#include <iostream>
#include <stack>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
#define wfor(i,j,k) for(i=j;i<k;++i)
#define mfor(i,j,k) for(i=j;i>=k;--i)
// void read(int &x) {
//  char ch = getchar(); x = 0;
//  for (; ch < '0' || ch > '9'; ch = getchar());
//  for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
// }
const int maxn = 50005;
int tree[maxn << 2];
void push_up(int id)
{
    tree[id] = tree[id << 1] + tree[id << 1 | 1];
}
void updata(int l, int r, int id, int pos, int number)//更新村庄状态,被摧毁就是1,没有就是0
{
    if (l == r)
    {
        tree[id] = number;
        return ;
    }
    int mid = (l + r) >> 1;
    if (mid >= pos)
        updata(l, mid, id << 1, pos, number);
    else
        updata(mid + 1, r, id << 1 | 1, pos, number);
    push_up(id);
}
int flag = 0;
void query(int l, int r, int id, int pos, int &x, int &y)//x,y是距离查询目标最近的左右断点位置
{
    if (flag)
        return;
    if (tree[id] == 0)//如果区间内没断点,那么直接返回
    {
        return ;
    }
    if (l == r)
    {
        if (tree[id] == 1)
        {
            if (l == pos)//如果查询目标就是被摧毁的直接返回,答案为0
            {
                flag = 1;
                return ;
            }
            if (l <= pos)//更新x,y的值
                x = max(x, l);
            else
                y = min(y, l);
        }
        return ;
    }
    int mid = (l + r) >> 1;
    if (mid >= x)
        query(l, mid, id << 1, pos, x, y);
    if (mid < y)
        query(mid + 1, r, id << 1 | 1, pos, x, y);
}
int des[maxn];//记录村庄是否被摧毁
int main()
{
    std::ios::sync_with_stdio(false);
    int n, m;
    while (cin >> n >> m)
    {
        int i;
        stack<int>last;
        memset(tree, 0, sizeof(tree));
        memset(des, 0, sizeof(des));
        wfor(i, 0, m)
        {
            char c;
            cin >> c;
            if (c == 'D')
            {
                int pos;
                cin >> pos;
                last.push(pos);//将被摧毁的村庄压入栈中
                des[pos] = 1;
                updata(1, n, 1, pos, 1);
            } else if (c == 'Q')
            {
                int pos;
                cin >> pos;
                int x = -1, y = 1e9;
                flag = 0;
                query(1, n, 1, pos, x, y);
                if (flag)//查询村庄被摧毁的情况
                {
                    cout << 0 << endl;
                } else//分类讨论查询目标的左右断点的情况
                {
                    int ans = 0;
                    if (x == -1 && y == 1e9)
                    {
                        ans = n;
                    } else if (x == -1)
                    {
                        ans = pos;
                        ans += y - pos - 1;
                    } else if (y == 1e9)
                    {
                        ans = pos - x;
                        ans += n - pos;
                    } else
                    {
                        ans += pos - x;
                        ans += y - pos - 1;
                    }
                    cout << ans << endl;
                }
            } else//重建村庄
            {
                while (des[last.top()] == 0)//如果村庄已经被重建则弹出找下一个
                {
                    last.pop();
                }
                updata(1, n, 1, last.top(), 0);
                des[last.top()] = 0;//标记村庄已经被重建
                last.pop();
            }
        }
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章