zoukankan      html  css  js  c++  java
  • P3979 遥远的国度 树剖

    P3979 遥远的国度 树剖

    题面

    需要想一下的树剖题,对于询问三需要处理换跟后的情况。我们以1为树根跑一遍剖分,对于换跟进行分类讨论,算出实际答案。讨论有三种情况:

    (以1为树根的树上)

    • 跟在询问节点的祖先上:因为不影响,所以直接求子树最小值

    • 跟即询问节点:直接查全树

    • 跟在询问节点子树中:画图容易得出,此时询问节点范围包含全树除了(son)的子树,其中(son)为跟向上跳达到询问节点的上一个节点。于是我们除去线段树区间([idx[son], idx[son]+sz[son]-1])分左右区间讨论就好了。

    #include <cstdio>
    #include <algorithm>
    #define MAXN 100010
    #define ll long long
    #define sl (x<<1)
    #define sr (x<<1|1)
    using namespace std;
    int head[MAXN],vv[MAXN*2],nxt[MAXN*2],tot;
    const int INF=0x3fffffff;
    inline void add_edge(int u, int v){
        vv[++tot]=v;
        nxt[tot]=head[u];
        head[u]=tot;
    }
    int nod_val[MAXN];
    int mxs[MAXN],sz[MAXN],dep[MAXN];
    int f[MAXN][20];
    void dfs1(int u, int fa){
        dep[u]=dep[fa]+1;
        f[u][0]=fa;
        for(int i=1;i<=17;++i)
            f[u][i]=f[f[u][i-1]][i-1];
        sz[u]=1;
        int mxsz=-1;
        for(int i=head[u];i;i=nxt[i]){
            int v=vv[i];
            if(v==fa) continue;
            dfs1(v, u);
            sz[u]+=sz[v];
            if(mxsz<sz[v]){
                mxsz=sz[v];
                mxs[u]=v;
            }
        }
    }
    int idx[MAXN],topf[MAXN],cnt,wnew[MAXN];
    void dfs2(int u, int top){
        idx[u]=++cnt;
        topf[u]=top;
        wnew[cnt]=nod_val[u];
        if(mxs[u]==0) return;
        dfs2(mxs[u], top);
        for(int i=head[u];i;i=nxt[i]){
            int v=vv[i];
            if(v==f[u][0]||v==mxs[u]) continue;
            dfs2(v, v);
        }
    }
    struct nod{
        int l, r;
        int val,lazy;
    } tre[MAXN*4];
    
    void buildt(int x, int l, int r){
        tre[x].l=l,tre[x].r=r,tre[x].lazy=0;
        if(l==r){
            tre[x].val=wnew[l];
            return;
        }
        int mid=(l+r)>>1;
        buildt(sl, l, mid);
        buildt(sr, mid+1, r);
        tre[x].val=min(tre[sl].val, tre[sr].val);
    }
    void push_down(int x){
        if(tre[x].lazy==0) return;
        tre[sl].lazy=tre[sl].val=tre[x].lazy;
        tre[sr].lazy=tre[sr].val=tre[x].lazy;
        tre[x].lazy=0;
    }
    void change(int x, int l, int r, int val){
        if(l<=tre[x].l&&tre[x].r<=r){
            tre[x].lazy=tre[x].val=val;
            return;
        }
        push_down(x);
        int mid=(tre[x].l+tre[x].r)>>1;
        if(l<=mid) change(sl, l, r, val);
        if(mid<r) change(sr, l, r, val);
        tre[x].val=min(tre[sl].val, tre[sr].val);
    }
    int query(int x, int l, int r){
        if(l<=tre[x].l&&tre[x].r<=r){
            return tre[x].val;
        }
        push_down(x);
        int mid=(tre[x].l+tre[x].r)>>1;
        int ans=INF;
        if(l<=mid) ans=min(query(sl, l, r), ans);
        if(mid<r) ans=min(query(sr, l, r), ans);
        return ans;
    }
    void tre_change(int a, int b, int val){
        while(topf[a]!=topf[b]){
            if(dep[topf[a]]<dep[topf[b]]) swap(a,b);
            change(1, idx[topf[a]], idx[a], val);
            a=f[topf[a]][0];
        }
        if(dep[a]<dep[b]) swap(a,b);
        change(1, idx[b], idx[a], val);
    }
    int tre_lca(int a, int b){
        while(topf[a]!=topf[b]){
            if(dep[topf[a]]<dep[topf[b]]) swap(a,b);
            a=f[topf[a]][0];
        }
        if(dep[a]<dep[b]) return a;
        return b;
    }
    int tre_query(int a){
        return query(1, idx[a], idx[a]+sz[a]-1);
    }
    int get_son(int a, int b){
        for(int i=17;i>=0;--i)
            if(dep[f[b][i]]>dep[a]) b=f[b][i];
        return b;
    }
    int n,q,cap;
    int main()
    {
        scanf("%d %d", &n, &q);
        for(int i=1;i<n;++i){
            int a,b;
            scanf("%d %d", &a, &b);
            add_edge(a, b);
            add_edge(b, a);
        }
        for(int i=1;i<=n;++i) scanf("%d", &nod_val[i]);
        scanf("%d", &cap);
        dfs1(1, 1);
        dfs2(1, 1);
        buildt(1, 1, n);
        while(q--){
            int opt;
            scanf("%d", &opt);
            if(opt==1){
                scanf("%d", &cap);
            }else if(opt==2){
                int l,r,v;
                scanf("%d %d %d", &l, &r, &v);
                tre_change(l, r, v);
            }else if(opt==3){
                int t;
                scanf("%d", &t);
                int lca=tre_lca(t, cap);
                if(t==cap) printf("%d
    ", query(1, 1, n));
                else if(lca!=t) printf("%d
    ", tre_query(t));
                else{
                    int son=get_son(t, cap);
                    int ans=min(query(1, 1, idx[son]-1), query(1, idx[son]+sz[son], n)); // 除去中间那个区间,分左右区间求
                    printf("%d
    ", ans);
                }
            }else puts("Erro!");
        }
        return 0;
    }
    
  • 相关阅读:
    Gradle构建模块化项目
    线程池的理解与应用
    Redis理解
    kafka监听出现的问题,解决和剖析
    shiro利用过期时间,解决用户冻结踢出问题
    信息系统的运行与维护包含的主要内容
    软件维护的内容是什么
    执行顺序
    Chrome/Edge 91版本SameSite by default cookies被移除后的解决方案
    公从号编程
  • 原文地址:https://www.cnblogs.com/santiego/p/11314817.html
Copyright © 2011-2022 走看看