题意:
有n个节点m次操作,操作有:D切断某个节点,R:恢复上次切断的节点,Q:询问某节点所在段的联通节点数目
思路:
对区间的各种操作与查询,考虑用线段树。
切断与恢复与线段树update的基本操作类似,查询与平常的求和不同,要先判断当前节点与询问节点间是否联通再去求和
PS:切断可以切断已经切断的点,恢复只用一次,且恢复上次切断操作的点
代码:
(询问没想到好的办法,感觉我写的好复杂0.0)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#define Clr(x) memset(x,0,sizeof(x))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define INF 0x33333333
#define LP(x,y) for(int i = x; i < y; i++)
#define LP2(x,y) for(int j = x; j >= y; j--)
using namespace std;
typedef long long LL;
//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int maxn = 140000;
int sum[maxn];
bool con[maxn];
stack<int> si;
int n,m,ans;
bool isd[maxn];
void pushup(int rt)
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
con[rt] = con[rt<<1] && con[rt<<1|1];
}
void build(int l,int r,int rt) //建树
{
if(l == r)
{
sum[rt] = 1;
con[rt] = true;
return;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
pushup(rt);
}
void des(int x,int l,int r,int rt) //摧毁x节点
{
if(l == r)
{
con[rt] = false;
return;
}
int m = (l + r) >> 1;
if(x <= m) des(x,lson);
if(x > m) des(x,rson);
pushup(rt);
}
bool queryL(int x,int l,int r,int rt) //查询x左边连通的数量
{
if(con[rt] && r <= x)
{
ans += sum[rt];
return true;
}
if(l == r && !con[rt]) return false;
int m = (l + r) >> 1;
bool res = true;
if(l <= x && x <= r) //x在当前根下
{
if(x <= m) queryL(x,lson); //在左子树
else
{
if(queryL(x,rson)) return res && queryL(x,lson); //右子树连通再递归左子树
}
}
else //x不在当前根下
{
if(queryL(x,rson)) return res && queryL(x,lson);
}
}
bool queryR(int x,int l,int r,int rt) //查询x右边连通的数量
{
if(con[rt] && l >= x)
{
ans += sum[rt];
return true;
}
if(l == r && !con[rt]) return false;
int m = (l + r) >> 1;
bool res = true;
if(l <= x && x <= r)
{
if(x > m) queryR(x,rson);
else
{
if(queryR(x,lson)) return res && queryR(x,rson);
}
}
else
{
if(queryR(x,lson)) return res && queryR(x,rson);
}
}
void cb(int x,int l,int r,int rt) //恢复
{
if(l == r)
{
con[rt] = true;
return;
}
int m = (l + r) >> 1;
if(x <= m) cb(x,lson);
if(x > m) cb(x,rson);
pushup(rt);
}
int main()
{
//freopen("out.txt","w",stdout);
while(~scanf("%d%d",&n,&m))
{
build(1,n,1);
Clr(isd);
char cmd[5];
int x;
while(m--)
{
scanf("%s",cmd);
if(cmd[0] == 'D')
{
scanf("%d",&x);
des(x,1,n,1);
si.push(x);
isd[x] = true;
}
else if(cmd[0] == 'R')
{
if(si.empty()) continue;
x = si.top(); si.pop();
while(!isd[x])
{
x = si.top(); si.pop();
}
isd[x] = false;
cb(x,1,n,1);
}
else if(cmd[0] == 'Q')
{
scanf("%d",&x);
ans = 0;
queryL(x,1,n,1);
queryR(x,1,n,1);
if(ans > 0) ans -= 1; //x节点被计算2次
printf("%d\n",ans);
}
}
}
}