题意:有第三种操作:
D x表示毁掉村庄x;
Q x表示询问x在内的最大连续的村庄;
R表示重建最近被毁掉的村庄
思路:用一个栈存储被毁掉的村庄,以便修复。开一个访问数组,如果村庄被毁掉则标记,查询的时候直接输出0;
然后线段树维护连续的村庄。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=50010;
int n,m;
bool vis[maxn];
stack<int> s;
struct IntervalTree
{
int ls[maxn<<3],rs[maxn<<3];
void maintain(int o,int l,int r)
{
ls[o]=ls[o<<1],rs[o]=rs[o<<1|1];
int mid=(l+r)>>1;
if(ls[o]==mid-l+1)ls[o]+=ls[o<<1|1];
if(rs[o]==r-mid)rs[o]+=rs[o<<1];
}
void build(int o,int l,int r)
{
ls[o]=rs[o]=0;
if(l==r)
{
ls[o]=rs[o]=1;
return;
}
int mid=(l+r)>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
maintain(o,l,r);
}
void update(int o,int l,int r,int pos,int x)
{
if(l==r)
{
ls[o]+=x;
rs[o]+=x;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid)update(o<<1,l,mid,pos,x);
else update(o<<1|1,mid+1,r,pos,x);
maintain(o,l,r);
}
int query(int o,int l,int r,int pos)//注意一下如何查询
{
int ans=0;
if(l==r)return 1;
int mid=(l+r)>>1;
if(pos<=mid)
{
if(pos>=mid-rs[o<<1]+1)return query(o<<1,l,mid,pos)+ls[o<<1|1];//如果在连续的那一段则要加上右孩子右面连续的一段;
else return query(o<<1,l,mid,pos);
}
else
{
if(pos<=mid+ls[o<<1|1])return query(o<<1|1,mid+1,r,pos)+rs[o<<1];
return query(o<<1|1,mid+1,r,pos);
}
}
}tree;
int main()
{
//freopen("in.txt","r",stdin);
char op[5];
int x;
scanf("%d%d",&n,&m);
tree.build(1,1,n);
memset(vis,0,sizeof(vis));
while(m--)
{
scanf("%s",op);
if(op[0]=='D')
{
scanf("%d",&x);
vis[x]=1;
tree.update(1,1,n,x,-1);
s.push(x);
}
else if(op[0]=='Q')
{
scanf("%d",&x);
if(vis[x])printf("0\n");
else printf("%d\n",tree.query(1,1,n,x));
}
else
{
x=s.top();s.pop();
vis[x]=0;
tree.update(1,1,n,x,1);
}
}
return 0;
}
现在用SBT重写一遍。
树中保存已经被摧毁的村庄,查询的时候只需要找到x的前驱跟后继,相减再减一就是区间长度
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=50010;
int vis[maxn];
int N,M;
stack<int> st;
int root,tot;
void init()
{
while(!st.empty())st.pop();
memset(vis,0,sizeof(vis));
root=tot=0;
}
struct SBT
{
int left,right,size,key;
void init(int val)
{
left=right=0;
key=val;
size=1;
}
}tree[maxn];
void left_rotate(int &x)
{
int y=tree[x].right;
tree[x].right=tree[y].left;
tree[y].left=x;
tree[y].size=tree[x].size;
tree[x].size=tree[tree[x].left].size+tree[tree[x].right].size+1;
x=y;
}
void right_rotate(int &x)
{
int y=tree[x].left;
tree[x].left=tree[y].right;
tree[y].right=x;
tree[y].size=tree[x].size;
tree[x].size=tree[tree[x].left].size+tree[tree[x].right].size+1;
x=y;
}
void maintain(int &x,int flag)
{
if(!flag)
{
if(tree[tree[tree[x].left].left].size>tree[tree[x].right].size)
right_rotate(x);
else if(tree[tree[tree[x].left].right].size>tree[tree[x].right].size)
left_rotate(tree[x].left),right_rotate(x);
else return;
}
else
{
if(tree[tree[tree[x].right].right].size>tree[tree[x].left].size)
left_rotate(x);
else if(tree[tree[tree[x].right].left].size>tree[tree[x].left].size)
right_rotate(tree[x].right),left_rotate(x);
else return;
}
maintain(tree[x].left,0);
maintain(tree[x].right,1);
maintain(x,0);
maintain(x,1);
}
//插入值为key的节点
void insert(int &x,int key)
{
if(!x)
{
x=++tot;
tree[x].init(key);
}
else
{
tree[x].size++;
if(key<tree[x].key)insert(tree[x].left,key);
else insert(tree[x].right,key);
maintain(x,key>=tree[x].key);
}
}
int del(int &x,int key)
{
if(!x)return 0;
tree[x].size--;
if(key==tree[x].key||(key<tree[x].key&&tree[x].left==0)||
(key>tree[x].key&&tree[x].right==0))
{
if(tree[x].left&&tree[x].right)
{
int p=del(tree[x].left,key+1);
tree[x].key=tree[p].key;
return p;
}
else
{
int p=x;
x=tree[x].left+tree[x].right;
return p;
}
}
else
return del(key<tree[x].key?tree[x].left:tree[x].right,key);
}
//返回值v的前驱的值,如果没有前驱返回v本身
int Pred(int t,int v)
{
if(!t)return v;
if(v<=tree[t].key)return Pred(tree[t].left,v);
else
{
int tmp=Pred(tree[t].right,v);
return v==tmp?tree[t].key:tmp;
}
}
//返回值v的后继的值,如果没有后继返回v本身
int Succ(int t,int v)
{
if(!t)return v;
if(v>=tree[t].key)return Succ(tree[t].right,v);
else
{
int tmp=Succ(tree[t].left,v);
return v==tmp?tree[t].key:tmp;
}
}
int main()
{
char op[5];
int x;
while(scanf("%d%d",&N,&M)!=EOF)
{
init();
while(M--)
{
scanf("%s",op);
if(op[0]=='D')
{
scanf("%d",&x);
//if(vis[x])continue;
vis[x]++;
st.push(x);
insert(root,x);
}
else if(op[0]=='R')
{
if(!st.empty())
{
del(root,st.top());
vis[st.top()]--;
if(vis[st.top()]<=0)st.pop();
}
}
else
{
scanf("%d",&x);
if(vis[x])printf("0\n");
else
{
int r=Succ(root,x);
if(r==x)r=N+1;
int l=Pred(root,x);
if(l==x)l=0;
printf("%d\n",r-l-1);
}
}
}
}
return 0;
}