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

    传送门

    这是一道好题啊……没有换根的话就是树剖板子题,但是加上换根怎么办?

    每次暴力重构dfs序?那不T死你……(突然想到自己动态点分治每次重新跑一遍点分治的sd思路)

    那么我们肯定是老套路,寻找修改根结点之后的不变量。我们先以最开始给定的根,来确定dfs序和其他一切一切的树剖基本工作。

    把路径全部修改成一个权值没什么难度,主要是看换根之后的访问问题。

    我们分三种情况讨论:

    1.根结点就是当前访问的点。

    这种情况非常好解决,直接输出整体最小值即可。

    2.根结点不在当前访问的节点的子树内。

    这个也很容易,因为根结点如果不在当前访问的子树内,那么这个点的子树原来是什么样现在还是什么样,没什么变化,直接访问即可。

    3.根结点在当前访问的子树内。

    这个稍微复杂,不过仔细思考之后发现,那就是这个点当前的子树,应该是整棵树减去当然根结点所在的子树。

    好像最稳定的方法是使用倍增求出来哪一个儿子是root所在的子树的根,之后访问其他的即可。不过我没有采取这种方式,而是用了一种更加暴力的方法:因为树剖保证了每棵子树内的dfs序一定是连续的,所以我们去掉这一段,直接访问剩下两端的最小值即可。怎么确定呢?我们枚举每一个子树,因为dfs序是连续的,所以如果root的dfs序在dfn[x] ~ dfn[x] + size[x] - 1之内,那么它就在这个子树之内。

    这个方法其实挺不稳定的,很容易被菊花图卡……不过其实跑的还挺快……

    看一下代码。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 100005;
    const int INF = 1000000009;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    struct edge
    {
        int next,to;
    }e[M<<1];
    
    struct seg
    {
        int v,lazy;
    }t[M<<2];
    
    int n,m,u,v,root,op,x,y,head[M],hson[M],size[M],dep[M],dfn[M],ecnt,fa[M],top[M],idx,def[M],rk[M];
    int nl,nr;
    
    void add(int x,int y)
    {
        e[++ecnt].to = y;
        e[ecnt].next = head[x];
        head[x] = ecnt;
    }
    
    void dfs1(int x,int f,int depth)
    {
        size[x] = 1,fa[x] = f,dep[x] = depth;
        int maxson = -1;
        for(int i = head[x];i;i = e[i].next)
        {
        if(e[i].to == f) continue;
        dfs1(e[i].to,x,depth+1);
        size[x] += size[e[i].to];
        if(size[e[i].to] > maxson) maxson = size[e[i].to],hson[x] = e[i].to;
        }
    }
    
    void dfs2(int x,int t)
    {
        top[x] = t,dfn[x] = ++idx,rk[idx] = def[x];
        if(!hson[x]) return;
        dfs2(hson[x],t);
        for(int i = head[x];i;i = e[i].next)
        {
        if(e[i].to == fa[x] || e[i].to == hson[x]) continue;
        dfs2(e[i].to,e[i].to);
        }
    }
    
    void build(int p,int l,int r)
    {
        if(l == r)
        {
        t[p].v = rk[l];
        return;
        }
        int mid = (l+r) >> 1;
        build(p<<1,l,mid),build(p<<1|1,mid+1,r);
        t[p].v = min(t[p<<1].v,t[p<<1|1].v);
    }
    
    void pushdown(int p,int l,int r)
    {
        int mid = (l+r) >> 1;
        t[p<<1].lazy = t[p<<1|1].lazy = t[p].lazy;
        t[p<<1].v = t[p<<1|1].v = t[p].lazy;
        t[p].lazy = 0;
    }
    
    void modify(int p,int l,int r,int kl,int kr,int val)
    {
        if(l == kl && r == kr)
        {
        t[p].v = t[p].lazy = val;
        return;
        }
        int mid = (l+r) >> 1;
        if(t[p].lazy) pushdown(p,l,r);
        if(kr <= mid) modify(p<<1,l,mid,kl,kr,val);
        else if(kl > mid) modify(p<<1|1,mid+1,r,kl,kr,val);
        else modify(p<<1,l,mid,kl,mid,val),modify(p<<1|1,mid+1,r,mid+1,kr,val);
        t[p].v = min(t[p<<1].v,t[p<<1|1].v);
    }
    
    int query(int p,int l,int r,int kl,int kr)
    {
        if(kl > kr) return INF;
        if(l == kl && r == kr) return t[p].v;
        int mid = (l+r) >> 1;
        if(t[p].lazy) pushdown(p,l,r);
        if(kr <= mid) return query(p<<1,l,mid,kl,kr);
        else if(kl > mid) return query(p<<1|1,mid+1,r,kl,kr);
        else return min(query(p<<1,l,mid,kl,mid),query(p<<1|1,mid+1,r,mid+1,kr));
    }
    
    int lca(int x,int y,bool flag,int val)
    {
        while(top[x] != top[y])
        {
        if(dep[top[x]] < dep[top[y]]) swap(x,y);
        if(flag) modify(1,1,n,dfn[top[x]],dfn[x],val);
        x = fa[top[x]];
        }
        if(dep[x] > dep[y]) swap(x,y);
        if(flag) modify(1,1,n,dfn[x],dfn[y],val);
        return x;
    }
    
    void findson(int x)
    {
        for(int i = head[x];i;i = e[i].next)
        {
        if(e[i].to == fa[x]) continue;
        if(dfn[e[i].to] <= dfn[root] && dfn[e[i].to] + size[e[i].to] - 1 >= dfn[root])
        {
            nl = dfn[e[i].to],nr = dfn[e[i].to] + size[e[i].to] - 1;
            return;
        }
        }
    }
    
    int main()
    {
        n = read(),m = read();
        rep(i,1,n-1) x = read(),y = read(),add(x,y),add(y,x);
        rep(i,1,n) def[i] = read();
        root = read();
        dfs1(root,0,1),dfs2(root,root),build(1,1,n);
        //rep(i,1,n) printf("%d ",dfn[i]);enter;
        rep(i,1,m)
        {
        op = read();
        if(op == 1) root = read();
        else if(op == 2) x = read(),y = read(),v = read(),lca(x,y,1,v);
        else if(op == 3)
        {
            //printf("#%d %d
    ",root,lca(x,root,0,0));
            x = read();
            if(x == root) printf("%d
    ",t[1].v);
            else if(lca(x,root,0,0) != x) printf("%d
    ",query(1,1,n,dfn[x],dfn[x] + size[x] - 1));
            else if(lca(x,root,0,0) == x)
            {
            findson(x);
            //printf("!%d %d
    ",nl,nr);
            int g = min(query(1,1,n,1,nl-1),query(1,1,n,nr+1,n));
            //g = min(query(1,1,n,dfn[x],dfn[x]),g);
            printf("%d
    ",g);
            }    
        }
        }
        return 0;
    }
  • 相关阅读:
    [UOJ#391]GEGEGE
    [GOODBYE WUXU][UOJ]
    codeforce 1110F
    [atcoder][abc123D]
    [atcoder][agc001]
    Luogu1070-道路游戏-动态规划
    Luogu 2577[ZJOI2005]午餐
    Luogu 1169 [ZJOI2007]棋盘制作
    Luogu 1273 有线电视网
    Luogu 2279 [HNOI2003]消防局的设立
  • 原文地址:https://www.cnblogs.com/captain1/p/9757407.html
Copyright © 2011-2022 走看看