由于题意简单,所以不解释为何用线段树,我用的是重口味线段树。
三方探查过后,大概可以把题意归纳为:
最开始所有点为1。
然后有一种操作,将此点置0(单点修改),这个应该都会。
第二种操作,将上一个被修改的点修复(单点修改),有时候会连续修好几个,所以你需要一个栈。
第三种操作,求与一个点相连的最长(区间查询),我求的是这个点左边最长1和右边最长1,然后相加。
二话不说上代码:
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
#define M (50005)
void Read(LL &x) {
x=0;
LL f=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-')
f=-f;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
x*=f;
return ;
}
LL le[M<<2],ri[M<<2],n,m=1,t,q,len[M<<2];
stack<LL>s;
void Build() {
for(int i=m - 1; i>=1; i--)
le[i]=le[i*2]+le[i*2+1],ri[i]=ri[i*2]+ri[i*2+1],len[i]=(len[i*2]+len[i*2+1]);
return ;
}
void Add(LL k,bool op) {
k+=m;
le[k]=ri[k]=op;
while(k) {
if(k%2) {
k--;
}
if(ri[k+1]==len[k+1])
ri[k/2]=ri[k+1]+ri[k];
else
ri[k/2]=ri[k+1];
if(le[k]==len[k])
le[k/2]=le[k+1]+le[k];
else
le[k/2]=le[k];
k>>=1;
}
return ;
}
void Query(LL L,LL R,LL &x,LL &y) {
LL s=m+L-1,t=m+R+1,ln=0,rn=0;
LL l1=0,l2=0,r1=0,r2=0;//不多解释,也就是左边的左,右边的左,右边的左,右边的右。因为左右不一定相连。
while(s||t) {
if(s>>1!=t>>1) {
if(!(s%2)) {
if(l1==ln)
l1=ln+le[s+1];
if(ri[s+1]==len[s+1])
r1+=len[s+1];
else
r1=ri[s+1];
ln+=len[s+1];
}
if(t%2) {
if(r2==rn)
r2=rn+ri[t-1];
if(le[t-1]==len[t-1])
l2+=le[t-1];
else
l2=le[t-1];
rn+=len[t-1];
}
}
s>>=1;
t>>=1;
}
if(l1==ln)
x=l1+l2;
else
x=l1;
if(r2==rn)
y=r2+r1;
else
y=r2;
return ;
}
int main() {
while(scanf("%lld %lld",&n,&q)==2) {
while(!s.empty())
s.pop();
memset(le,0,sizeof(le));
memset(ri,0,sizeof(ri));
memset(len,0,sizeof(len));
m=1;
while(m < n + 2)
m <<= 1;
for(int i = 1; i <= n; i ++)
le[m+i]=1,ri[m+i]=1,len[m+i]=1;
Build();
char ck[10];
while(q--) {
scanf("%s",ck);
if(ck[0]=='R') {
if(s.empty())
continue;
Add(s.top(),1);
s.pop();
continue;
}
LL a;
Read(a);
if(ck[0]=='Q'){
if(!ri[a+m]){//判断这个点为不为0,
puts("0");
continue;
}
LL l1=0,l2=0,r1=0,r2=0;
Query(1,a-1,l1,r1);
Query(a+1,n,l2,r2);
printf("%lld\n",r1+l2+1);
}
if(ck[0]=='D') {
Add(a,0);
s.push(a);
}
}
}
}