在抗日战争期间,华北平原广大地区进行了大规模的隧道战。 一般来说,通过隧道连接的村庄排成一列。 除了两端,每个村庄都与两个相邻的村庄直接相连。 入侵者经常对一些村庄发动袭击并摧毁其中的部分隧道。 八路军指挥官要求最新的隧道和村庄连接状态。 如果某些村庄严重隔离,必须立即恢复连接!
Input
输入的第一行包含两个正整数n和m(n,m≤50,000),表示村庄和事件的数量。 接下来的m行中的每一行描述一个事件。 以下所示的不同格式描述了三种不同的事件: D x:第x个村庄被毁。 Q x:指挥官询问第x个村庄与其直接或间接相关的村庄数量。 R:最后毁坏的村庄被重建了。
Output
按顺序输出每个指挥官询问的答案。
Sample Input
7 9 D 3 D 6 D 5 Q 4 Q 5 R Q 4 R Q 4
Sample Output
1 0 2 4
Sponsor
定义线段树:
ll 记录区间左端点开始的最大连续个数, rr 记录区间右端点开始的最大的连续个数,
ml表示该区间最大的连续点的个数。
struct node{ int l,r; int ll,rr,ml; //左边连续的最长长度和右边连续的最长点长度 //以及这个区间最长连续点长度 }t[maxn];
建树:
void build(int p,int l,int r){ t[p].l=l; t[p].r=r; t[p].ll=t[p].rr=t[p].ml=r-l+1; //初始左连续长度和右连续长的和最长的连续长度都为r-l+1 if(l==r){ return ; } int mid=(t[p].l+t[p].r)/2; build(p*2,l,mid); build(p*2+1,mid+1,r); }
更新:
void update(int p,int x,int val){ if(t[p].l==t[p].r){ t[p].ll=t[p].rr=t[p].ml=val; return ; } if(x<=t[2*p].r){ update(2*p,x,val); } else{ update(2*p+1,x,val); } //更新正个区间 t[p].ml=max(t[2*p].ml,t[2*p+1].ml);//可能有断层l---1 1--mid ,mid----1 1-----r t[p].ml=max(t[p].ml,t[2*p].rr+t[2*p+1].ll);//左区间最右,和右区间的最左 //更新左区间 t[p].ll=t[2*p].ll; if(t[p].ll==t[2*p].r-t[2*p].l+1){//左边都是要加上右边 t[p].ll+=t[2*p+1].ll; } t[p].rr=t[2*p+1].rr; if(t[p].rr==(t[2*p+1].r-t[2*p+1].l+1)){ t[p].rr+=t[2*p].rr;//左边的加左边的 } }
查询:
int query(int p,int x){//寻找区间连续最大值 if(t[p].l==t[p].r||t[p].ml==t[p].r-t[p].l+1||t[p].ml==0){ return t[p].ml; } if(x<=t[2*p].r){ if(x>=t[2*p].r-t[2*p].rr+1){//边界可能右区间的还有 return query(2*p,x)+query(2*p+1,t[2*p+1].l); } else{ return query(2*p,x); } } else{//或者说x<=t[2*p+1].r+t[2*p+1].ll-1; if(x<=t[2*p].r+t[2*p+1].ll){//可能右区间还有 return query(2*p,t[2*p].r)+query(2*p+1,x); } else{ query(2*p+1,x); } } }
#include<iostream> #include<algorithm> using namespace std; const int maxn=1e6+100; int top; int q[maxn]; struct node{ int l,r; int ll,rr,ml; //左边连续的最长长度和右边连续的最长点长度 //以及这个区间最长连续点长度 }t[maxn]; void build(int p,int l,int r){ t[p].l=l; t[p].r=r; t[p].ll=t[p].rr=t[p].ml=r-l+1; //初始左连续长度和右连续长的和最长的连续长度都为r-l+1 if(l==r){ return ; } int mid=(t[p].l+t[p].r)/2; build(p*2,l,mid); build(p*2+1,mid+1,r); } void update(int p,int x,int val){ if(t[p].l==t[p].r){ t[p].ll=t[p].rr=t[p].ml=val; return ; } if(x<=t[2*p].r){ update(2*p,x,val); } else{ update(2*p+1,x,val); } //更新正个区间 t[p].ml=max(t[2*p].ml,t[2*p+1].ml);//可能有断层l---1 1--mid ,mid----1 1-----r t[p].ml=max(t[p].ml,t[2*p].rr+t[2*p+1].ll);//左区间最右,和右区间的最左 //更新左区间 t[p].ll=t[2*p].ll; if(t[p].ll==t[2*p].r-t[2*p].l+1){//左边都是要加上右边 t[p].ll+=t[2*p+1].ll; } t[p].rr=t[2*p+1].rr; if(t[p].rr==(t[2*p+1].r-t[2*p+1].l+1)){ t[p].rr+=t[2*p].rr;//左边的加左边的 } } int query(int p,int x){//寻找区间连续最大值 if(t[p].l==t[p].r||t[p].ml==t[p].r-t[p].l+1||t[p].ml==0){ return t[p].ml; } if(x<=t[2*p].r){ if(x>=t[2*p].r-t[2*p].rr+1){//边界可能右区间的还有 return query(2*p,x)+query(2*p+1,t[2*p+1].l); } else{ return query(2*p,x); } } else{//或者说x<=t[2*p+1].r+t[2*p+1].ll-1; if(x<=t[2*p].r+t[2*p+1].ll){//可能右区间还有 return query(2*p,t[2*p].r)+query(2*p+1,x); } else{ query(2*p+1,x); } } } int main(){ int n,m; char str[10]; int x; while(~scanf("%d%d",&n,&m)){ build(1,1,n); top=0; for(int i=1;i<=m;i++){ scanf("%s",str); if(str[0]=='D'){ scanf("%d",&x); q[++top]=x; update(1,x,0); //摧毁 } else if(str[0]=='Q'){ scanf("%d",&x); printf("%d ",query(1,x)); } else{ x=q[top--]; update(1,x,1);//重建 } } } }