• 线段树维护连续区间


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

    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);//重建 
                }
            }
        }
    } 
  • 相关阅读:
    SpringBoot-14-MyBatis预热篇,MySQL小结
    SpringBoot-13-插曲之Node文件重命名+自动生成json对象
    八月十九风雨大作
    诉世书
    《仪式》
    珊瑚墓地
    新生
    《应龙》
    《枝·你是树的狂舞》
    golang中使用etcd
  • 原文地址:https://www.cnblogs.com/lipu123/p/13959005.html
Copyright © 2020-2023  润新知