题意:有n个村庄,每个村庄都用地道连接着,分为三种操作,R表示修复最后一个被破坏的村庄,D x表示破话村庄x, Q x表示求包括村庄x的最长连续区间。
思路:线段树的区间合并题目,对于求一个连续最长区间,分三种情况,①是左子树最长连续区间,②是右子树最长连续区间,③是左子树最长右连续区间+右子树最长左连续区间的值,这三种情况取最大值即可。具体可看代码注释,很详细。
#include <cstdio>
#include <stack>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
const int maxn = 5e4 + 10;
int n,m,s[maxn],top;
char op[3];
struct node{
int l,r; //以rt为根结点的左右区间l表示左端点,r表示右端点
int ls,rs,ms;//ls:左起最大连续区间,rs:右起最大连续区间 ms:最大连续区间
}p[maxn << 2];
void build(int l, int r, int rt){//建树 & 初始化
p[rt].l = l; p[rt].r = r; //以rt为根结点的左右区间[l,r]
p[rt].ls = p[rt].ms = p[rt].rs = r - l + 1; //初始该区间的所有值均为1,故为区间大小
if(l != r){
int m = (l + r) >> 1;
build(l,m,rt << 1);
build(m+1,r,rt << 1 | 1);
}
}
void update(int rt, int x, int flag){//更新x节点的状态
if(p[rt].l == p[rt].r){
if(flag) p[rt].ls = p[rt].ms = p[rt].rs = 1; //修复
else p[rt].ls = p[rt].ms = p[rt].rs = 0; //破坏
return ;
}
int m = (p[rt].l + p[rt].r) >> 1;
if(x <= m) update(rt << 1,x,flag); //要破坏或者修复的点在左子树
else update(rt << 1 | 1,x,flag); //要破坏或者修复的点在右子树
p[rt].ls = p[rt << 1].ls; //父节点的左区间最大连续长度等与左子树的,
p[rt].rs = p[rt << 1 | 1].rs; //着重分析最后两个if语句
p[rt].ms = max(max(p[rt << 1].ms,p[rt << 1 | 1].ms),p[rt << 1].rs + p[rt << 1 | 1].ls);
//区间的最大连续区间分三种情况:左子树最大连续区间,右子树最大连续区间,左子树右连续+右子树左连续
if(p[rt << 1].ls == p[rt << 1].r - p[rt << 1].l + 1) p[rt].ls += p[rt << 1 | 1].ls;
//左子树的左连续区间长度等于 左子树区间大小,则其父节点的长度应为加上右子树左连续长度
if(p[rt << 1 | 1].rs == p[rt << 1 | 1].r - p[rt << 1 | 1].l + 1) p[rt].rs += p[rt << 1].rs;
//右子树右连续长度等于右子树区间大小,则其父节点的长度为再加上左子树的右连续的长度
}
int query(int rt, int x){//查询含有节点x的最长连续区间
//找到x节点或者最长连续区间为0或者区间值全为1
if(p[rt].l == p[rt].r || p[rt].ms == 0 || p[rt].ms == p[rt].r - p[rt].l + 1)
return p[rt].ms;
int m = (p[rt].l + p[rt].r) >> 1;
if(x <= m){ //当前结点在左子树
//当前节点大于等于左子树右连续区间的左端点值 ,则要再计算上右子树的左连续区间
if(x >= p[rt << 1].r - p[rt << 1].rs + 1)
return query(rt << 1,x) + query(rt << 1 | 1,m+1);
else
return query(rt << 1,x);
}
else{//当前节点小于等于右子树左连续区间的右端点值,则要计算上左子树的右连续区间
if(x <= p[rt << 1 | 1].l + p[rt << 1 | 1].ls - 1)
return query(rt << 1 | 1,x) + query(rt << 1, m);
else
return query(rt << 1 | 1,x);
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
build(1,n,1);
int num;
top = 0;
while(m --){
scanf("%s",op);
if(op[0] == 'R'){
if(num > 0){
num = s[-- top];
update(1,num,1);
}
}
else{
scanf("%d",&num);
if(op[0] == 'D'){
s[top ++] = num;
update(1,num,0);
}
else{
printf("%d\n",query(1,num));
}
}
}
}
return 0;
}