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;
}

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