题意:1-n个地道,m个次操作,D代表摧毁第i个地道,Q代表查询包含第i个地道的最大连续地道数目,并输出。R代表修复最近摧毁的那个地道;
思路:这题利用了线段树的相邻结点区间是连续的特性,而且是维护连续的1,所以用llen、rlen、len数组分别表代表当前结点的1的最长连续前缀长、最长连续后缀长,最长连续区间长,对于某个结点,它的最长连续前缀等于它的左子结点的最长连续前缀,如果它的左子结点的最长连续前缀包含了整个左子区间,那么这个结点的最长连续前缀还要加上右子结点的最长连续前缀;同理,对于某个结点的最长连续后缀是一样的,这里不赘述。而对于某个结点的最长连续区间应该是它的最长连续前缀、最长连续后缀、它的左子结点的最长连续后缀+右子结点的最长连续前缀 三者中的最大值,所以pushUp函数就可以写出来了。建树和更新的时候直接在l==r的时候赋值即可。对于查询,代码注释已经给出,画一下图很好理解的。
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn=50005;
const int mod=1e9+7;
const double eps=1e-8;
const double PI = acos(-1.0);
#define lowbit(x) (x&(-x))
int len[maxn<<2],llen[maxn<<2],rlen[maxn<<2];
void pushUp(int rt,int length)
{
llen[rt]=llen[rt<<1]; //当前结点的最长连续前缀=左子结点的最长连续前缀
rlen[rt]=rlen[rt<<1|1];
if(llen[rt<<1]==(length-(length>>1))) llen[rt]+=llen[rt<<1|1];
//如果左子结点的最长连续前缀为整个左子区间,那么本结点的前缀还要加上右子区间的最长前缀
if(rlen[rt<<1|1]==(length>>1)) rlen[rt]+=rlen[rt<<1];
len[rt]=max(max(len[rt<<1],len[rt<<1|1]),rlen[rt<<1]+llen[rt<<1|1]);
}
void build(int l,int r,int rt)
{
if(l==r)
{
len[rt]=llen[rt]=rlen[rt]=1;
return ;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushUp(rt,r-l+1);
}
void update(int loc,int C,int l,int r,int rt)
{
if(l==r)
{
len[rt]=llen[rt]=rlen[rt]=C;
return ;
}
int m=(l+r)>>1;
if(loc<=m) update(loc,C,l,m,rt<<1);
if(loc>m) update(loc,C,m+1,r,rt<<1|1);
pushUp(rt,r-l+1);
}
int query(int loc,int l,int r,int rt)
{
if(l==r) return len[rt];
int m=(l+r)>>1;
if(loc<=m)
{
if(loc+rlen[rt<<1]>m) return rlen[rt<<1]+llen[rt<<1|1];
//如果loc在左子区间的最长后缀和右子区间的最长前缀中,直接输出这两个前后缀之和即可
else return query(loc,l,m,rt<<1);
//否则的话,继续向左子节点查询
}
else
{
if(m+llen[rt<<1|1]>=loc) return rlen[rt<<1]+llen[rt<<1|1];
//因为右子区间是(mid,r]左开区间,所以这里判断loc是否在右子区间的前缀的范围内用的是 ">="
else return query(loc,m+1,r,rt<<1|1);
}
}
int main()
{
std::ios::sync_with_stdio(false);
int n,m;
while(cin>>n>>m)
{
build(1,n,1);
int tot=0,stk[maxn];
while(m--)
{
char c;
cin>>c;
if(c=='D')
{
int loc;
cin>>loc;
stk[++tot]=loc;
update(loc,0,1,n,1);
}
else if(c=='R')
{
int loc=stk[tot--];
update(loc,1,1,n,1);
}
else
{
int loc;
cin>>loc;
cout<<query(loc,1,n,1)<<endl;
}
}
}
return 0;
}