题意:一条线上的点,D x是破坏这个点,Q x是表示查询以x所在的最长的连续的点的个数,R是恢复上一次破坏的点。
分析:还是最大连续区间的板题,不过就是变成了单个节点进行更新。直接套用板子稍微更改就好,
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int maxn=5e4+10;
struct node{
int ls,rs,ms;
}tree[maxn*4];
int n,m;
void build_tree(int l,int r,int i){
tree[i].ls=tree[i].rs=tree[i].ms=r-l+1;
if(l==r) return;
int mid=l+r>>1;
build_tree(l,mid,i<<1);
build_tree(mid+1,r,i<<1|1);
}
bool all_space(int l,int r,int i){
if(tree[i].ls==r-l+1) return 1;
return 0;
}
int query(int t,int l,int r,int i){
if(l==r||tree[i].ms==r-l+1||tree[i].ms==0){
return tree[i].ms;
}
int mid=l+r>>1;
if(t<=mid){
if(t>=mid-tree[i<<1].rs+1){
return query(t,l,mid,i<<1)+query(mid+1,mid+1,r,i<<1|1);
}else return query(t,l,mid,i<<1);
}else{
if(t<=mid+tree[i<<1|1].ls){
return query(t,mid+1,r,i<<1|1)+query(mid,l,mid,i<<1);
}else return query(t,mid+1,r,i<<1|1);
}
}
void change(int t,int l,int r,int i,int flag){
if(l==r){
if(!flag){
tree[i].ls=tree[i].rs=tree[i].ms=0;
}else{
tree[i].ls=tree[i].rs=tree[i].ms=1;
}
return;
}
int mid=l+r>>1;
if(t<=mid) change(t,l,mid,i<<1,flag);
else change(t,mid+1,r,i<<1|1,flag);
tree[i].ls=tree[i<<1].ls;
if(all_space(l,mid,i<<1))
tree[i].ls+=tree[i<<1|1].ls;
tree[i].rs=tree[i<<1|1].rs;
if(all_space(mid+1,r,i<<1|1))
tree[i].rs+=tree[i<<1].rs;
tree[i].ms=max(tree[i<<1].rs+tree[i<<1|1].ls,max(tree[i<<1].ms,tree[i<<1|1].ms));
}
int main()
{
while(~scanf("%d%d",&n,&m)){
stack<int> st;
memset(tree,0,sizeof tree);
build_tree(1,n,1);
while(m--){
char ch;
int a;
scanf(" %c",&ch);
if(ch=='D'){
scanf("%d",&a);
change(a,1,n,1,0);
st.push(a);
}else if(ch=='Q'){
scanf("%d",&a);
printf("%d\n",query(a,1,n,1));
}else{
if(st.empty()) continue;
change(st.top(),1,n,1,1);
st.pop();
}
}
}
return 0;
}