• hdu 1540 Tunnel Warfare (线段树维护一维联通区间)


    • 题意: 一维线段上n个点,有摧毁和修复两种操作,询问某点最大的可达区域
    • 思路: 线段树维护(lsum)代表区间左端点开始最长联通区域,(rsum)代表右端点开始最长联通区域.单点修改只有(push_up)操作,用左子树(lsum)更像(lsum),右子树(rsum)更新(rsum)
    #include<string>
    #include<vector>
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<stack>
    #define ll long long
    #define FOR(i,l,r) for(int i = l ; i <= r ;++i )
    #define inf 1<<30
    #define EPS (1e-9)
    #define lson(p) (p<<1)
    #define rson(p) (p<<1|1)
    using namespace std;
    typedef pair<int,int> pii;
    const int N = 5e5+30;
    int n,m;
    struct node{
        int l,r;
        int lsum,rsum;
    }a[N<<2];
    
    void push_up(int rt){
        a[rt].lsum = a[lson(rt)].lsum;  // 左二子更新左端点
        a[rt].rsum = a[rson(rt)].rsum;  // 右儿子更新右端点
        if(a[lson(rt)].lsum + a[lson(rt)].l-1 == a[lson(rt)].r){
            // 左儿子完全覆盖 扩充左区间
            a[rt].lsum  += a[rson(rt)].lsum;
        }
        if(a[rson(rt)].r - a[rson(rt)].rsum +1 == a[rson(rt)].l){
            // 右儿子完全覆盖 扩充右区间
            a[rt].rsum += a[lson(rt)].rsum;
        }
    }
    
    void build(int rt,int l,int r){
        a[rt].lsum = a[rt].rsum = r-l+1;
        a[rt].l = l; a[rt].r = r;
        if(l==r)  return ;
        int mid = (l+r)>>1;
        build(lson(rt),l,mid);
        build(rson(rt),mid+1,r);
    }
    
    
    void update(int rt,int p,int v){
        // 单点更新
        if(a[rt].l==p && a[rt].r ==p){
            a[rt].lsum = v;
            a[rt].rsum = v;
            return ;
        }
        int mid = (a[rt].l + a[rt].r)>>1;
        if(p<=mid)  update(lson(rt),p,v);
        else if(p>mid)   update(rson(rt),p,v);
        push_up(rt);
    }
    
    int query(int rt,int p){
        // 单点
        if(a[rt].l == a[rt].r )
            return a[rt].lsum;
        int mid = (a[rt].l + a[rt].r) >> 1;
        if(p<=mid){
            // p 在 左儿子的连续区间中,  左儿子的右区间与右儿子的左区间一定相邻 直接返回和
            if(p >= a[lson(rt)].r - a[lson(rt)].rsum +1){
                return a[lson(rt)].rsum + a[rson(rt)].lsum;
            }else{ // 否则递归查询左儿子
                return query(lson(rt),p);
            }
        }else{
            if(p <= a[rson(rt)].lsum + a[rson(rt)].l-1){
                return a[lson(rt)].rsum + a[rson(rt)].lsum;
            }else{
                return query(rson(rt),p);
            }
        }
    
    }
    char op[20];
    void solve(){
        stack<int> st;
        build(1,1,n);
        int pos ;
        FOR(i,1,m){
            scanf("%s",op);
            if(op[0]=='D'){
                scanf("%d",&pos);
                st.push(pos);
                update(1,pos,0);
            }else if(op[0]=='Q'){
                scanf("%d",&pos);
                printf("%d
    ",query(1,pos));
            }else{
                pos = st.top(); st.pop();
                update(1,pos,1);
            }
        }
    }
    int main(){
        while(scanf("%d%d",&n,&m)!=EOF){
            solve();
        }
        return 0;
    }
    
    

    当前节点与左右子节点区间的关系要搞清楚,只有单点修改,所以只存在用儿子更新父亲的情况.

  • 相关阅读:
    Codeforces Round #687 A. Prison Break
    最小生成树自用笔记(Kruskal算法+prim算法)
    Codeforces Round #686 (Div. 3)(A->D)(模拟,vector,数学)
    Acwing 852. spfa判断负环
    Linux内核分析_课程学习总结报告
    结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程
    深入理解系统调用
    基于mykernel 2.0编写一个操作系统内核
    何评测一个软件工程师的计算机网络知识水平与网络编程技能水平?——参考试题
    TCP三次握手Linux源码解析
  • 原文地址:https://www.cnblogs.com/xxrlz/p/11360510.html
Copyright © 2020-2023  润新知