题目链接: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;
}