线段树维护连续区间

在抗日战争期间,华北平原广大地区进行了大规模的隧道战。 一般来说,通过隧道连接的村庄排成一列。 除了两端,每个村庄都与两个相邻的村庄直接相连。
入侵者经常对一些村庄发动袭击并摧毁其中的部分隧道。 八路军指挥官要求最新的隧道和村庄连接状态。 如果某些村庄严重隔离,必须立即恢复连接!

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\n",query(1,x));
            }
            else{
                x=q[top--];
                update(1,x,1);//重建 
            }
        }
    }
} 

 

posted @ 2020-11-11 15:37  哎呦哎(iui)  阅读(135)  评论(0编辑  收藏  举报