題目鏈接: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;
}