- Tunnel Warefare
- 题意
可以理解为开始的时候有一条链,有三种操作:
1、D n :将链从位置n的地方断开
2、R : 将上一个断开的位置接上
3、Q n:包含位置n的最大连续链的长度 - 题解
因为是写的线段树的专题,而且看操作明显也是线段树,但是想了好久也没有想明白用线段树维护什么,看了其他大佬的博客才顿悟。
线段树的节点需要维护三个变量
maxx:该区间内最大的连续链的长度
lmax:从左端点开始往右扩展的最大连续的长度
rmax:从右端点开始往左扩展的最大连续的长度
具体的解释都写在代码中了
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long ul;
typedef unsigned long long ull;
#define pi acos(-1.0)
#define e exp(1.0)
#define pb push_back
#define mk make_pair
#define fir first
#define sec second
#define scf scanf
#define prf printf
typedef pair<ll,ll> pa;
const int dir_4[4][2]={-1,0,0,1,1,0,0,-1};
const int dir_8[8][2]={-1,-1,-1,0,-1,1,0,1,1,1,1,0,1,-1,0,-1};
const ll INF=0x3f3f3f3f3f3f3f3f;
const int inf=0x3f3f3f3f;
const int MAX_N=5e4+7;
struct Node{
int l,r,maxx,lmax,rmax;
Node(){}
Node(int l,int r,int maxx,int lmax,int rmax):l(l),r(r),maxx(maxx),lmax(lmax),rmax(rmax){}
int mid(){
return (l+r)>>1;
}
int len(){
return (r-l+1);
}
}node[MAX_N<<2];
void pushup(int rt){
//maxx;要么是左右儿子的maxx的最大值,或者是左儿子的rmax和右儿子的lmax拼接起来的值
node[rt].maxx=max(max(node[rt<<1].maxx,node[rt<<1|1].maxx),node[rt<<1].rmax+node[rt<<1|1].lmax);
//lmax:如果左儿子包含的整个区间是连续的,那么还得加上右儿子的lmax
node[rt].lmax=node[rt<<1].lmax+(node[rt<<1].lmax==node[rt<<1].len()?node[rt<<1|1].lmax:0);
//rmax:如果右儿子包含的整个区间是连续的,那么还得加上左儿子的rmax
node[rt].rmax=node[rt<<1|1].rmax+(node[rt<<1|1].rmax==node[rt<<1|1].len()?node[rt<<1].rmax:0);
return ;
}
void built_tree(int rt,int l,int r){
node[rt]=Node(l,r,1,1,1);
if(l==r)
return ;
int m=node[rt].mid();
built_tree(rt<<1,l,m);
built_tree(rt<<1|1,m+1,r);
pushup(rt);//更新父节点
return ;
}
void update(int rt,int tar,int var){
if(node[rt].l==tar&&node[rt].r==tar){
node[rt]=Node(tar,tar,var,var,var);
return ;
}
int m=node[rt].mid();
if(tar<=m)
update(rt<<1,tar,var);
else
update(rt<<1|1,tar,var);
pushup(rt);//修改之后更新
return ;
}
int query(int rt,int tar){
if(!node[rt].maxx||node[rt].l==node[rt].r)
return node[rt].maxx;//如果函数从这个地方返回的,说明该节点包含的整个区间肯定是连续的
int m=node[rt].mid();
if(tar<=m){
//如果tar在左儿子rmax包含的区间中,答案还得加上右儿子的lmax
if(tar>=node[rt<<1].r-node[rt<<1].rmax+1){
return node[rt<<1].rmax+node[rt<<1|1].lmax;
}
//否则继续找
return query(rt<<1,tar);
}
else{
//如果tar在右儿子lmax包含的区间中,答案还得加上左儿子的rmax
if(tar<=node[rt<<1|1].l+node[rt<<1|1].lmax-1){
return node[rt<<1|1].lmax+node[rt<<1].rmax;
}
//否则继续找
return query(rt<<1|1,tar);
}
}
int N,M;
stack<int>st;//用来存储被断开的链点
int main()
{
// freopen(".../.txt","w",stdout);
// freopen(".../.txt","r",stdin);
// ios::sync_with_stdio(false);
int i,j,k,n;
//多组输入。不然WA给你看
while(~scf("%d %d",&N,&M)){
built_tree(1,1,N);
while(!st.empty())
st.pop();
while(M--){
string s;
cin>>s;
if(s[0]=='D'){
scf("%d",&n);
st.push(n);
update(1,n,0);
}
else if(s[0]=='Q'){
scf("%d",&n);
int res=query(1,n);
prf("%d\n",res);
}
else if(!st.empty()){
n=st.top();
st.pop();
update(1,n,1);
}
}
}
return 0;
}