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

    https://www.luogu.org/problemnew/show/P3979

    3种情况

     x=root,很显然此时应当查询整棵树

    lca(root,x)!=x ,此时直接查询x的子树即可,与换根无关

    lca(root,x)=x,此时我们应当查询与x相邻的节点中与root最近的点v在整棵树中的补集

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #define lson l, mid, rt << 1
    #define rson mid + 1, r, rt << 1 | 1
    using namespace std;
    
    typedef long long ll;
    typedef double dd;
    const int maxn=200010;
    const ll INF = (ll)1E14 + 9;
    
    int h[maxn], n, m, top[maxn], lca[maxn][21], son[maxn], edge, sz[maxn], dep[maxn];
    int L[maxn], R[maxn], root, num, x, y, tx, ty, t, opt;
    ll val, a[maxn];
    
    struct Edge {
        int to, ne;
    } e[maxn * 2];
    
    struct Seg {
        ll minn, same;
    } seg[maxn << 2];
    
    void close() {
        exit(0);
    }
    
    void addedge(int x,int y) {
        e[edge].to = y;
        e[edge].ne = h[x];
        h[x] = edge++;
    }
    
    void dfs(int k,int from) {
        sz[k] = 1;
        dep[k] = dep[from] + 1;
        son[k] = 0;
        for (int p=h[k]; p!=-1; p=e[p].ne) {
            int to = e[p].to;
            if (to == from) continue;
            lca[to][0] = k;
            for (int i=1; i<=20; i++)
                lca[to][i] = lca[lca[to][i-1]][i-1];
            dfs(to, k);
            sz[k] += sz[to];
            if (sz[to] > sz[son[k]]) son[k] = to;
        }
    }
    
    void build(int k,int from) {
        L[k] = ++num;
        top[k] = from;
        if (son[k]) build(son[k], from);
        for (int p=h[k]; p!=-1; p=e[p].ne) {
            int to = e[p].to;
            if (to != lca[k][0] && to != son[k])
                build(to, to);
        }
        R[k] = num;
    }
    
    int get_lca(int x,int y) {
        if (dep[x] < dep[y]) swap(x, y);
        int depth = dep[x] - dep[y];
        for (int i=20; i>=0; i--)
            if (depth & (1 << i))
                x = lca[x][i];
        if (x == y) return x;
        for (int i=20; i>=0; i--) {
            if (lca[x][i] != lca[y][i]) {
                x = lca[x][i];
                y = lca[y][i];
            }
        }
        return lca[x][0];
    }
    
    void pushup(int rt) {
        seg[rt].minn = min(seg[rt<<1].minn, seg[rt<<1|1].minn);
    }
    
    void same(int rt,ll val) {
        seg[rt].minn = val;
        seg[rt].same = val;
    }
    
    void pushdown(int rt) {
        if (seg[rt].same) {
            same(rt << 1, seg[rt].same);
            same(rt << 1 | 1, seg[rt].same);
            seg[rt].same = 0;
        }
    }
    
    void change(int L,int R,ll val,int l,int r,int rt) {
        if (L <= l && r <= R) {
            same(rt, val);
            return;
        }
        int mid = (l + r) >> 1;
        pushdown(rt);
        if (L <= mid)
            change(L,R,val,lson);
        if (mid + 1 <= R)
            change(L,R,val,rson);
        pushup(rt);
    }
    
    ll query(int L,int R,int l,int r,int rt) {
        if (L > R) return INF;
        if (L <= l && r <= R) {
            return seg[rt].minn;
        }
        int mid = (l + r) >> 1;
        pushdown(rt);
        ll ans = INF;
        if (L <= mid)
            ans = min(ans, query(L,R,lson));
        if (mid + 1 <= R)
            ans = min(ans, query(L,R,rson));
        pushup(rt);
        return ans;
    }
    
    void cc() {
        tx = top[x];
        ty = top[y];
        while (tx != ty) {
            if (dep[tx] < dep[ty]) {
                swap(x, y);
                swap(tx, ty);
            }
            change(L[tx], L[x], val, 1, n, 1);
            x = lca[tx][0];
            tx = top[x];
        }
        if (dep[x] < dep[y])
            swap(x, y);
        change(L[y], L[x], val, 1, n, 1);
    }
    
    void work() {
        if (root == x) {
            printf("%lld
    ", seg[1].minn);
            return;
        }
        t = get_lca(root, x);
        if (t != x) { 
            printf("%lld
    ", query(L[x], R[x], 1, n, 1));
            return;
        }
        int depth = dep[root] - dep[x] - 1;
        int haha = root;
        for (int i=20; i>=0; i--)
            if (depth & (1 << i))
                haha = lca[haha][i];
        printf("%lld
    ", min(query(1, L[haha] - 1, 1, n, 1), query(R[haha] + 1, n, 1, n, 1)) );
    }
    
    void init() {
        scanf("%d %d",&n,&m);
        memset(h, -1, sizeof(h));
        for (int i=1; i<=n-1; i++) {
            scanf("%d %d",&x, &y);
            addedge(x, y);
            addedge(y, x);
        }
        for (int i=1; i<=n; i++)
            scanf("%lld",&a[i]);
        dfs(1, 0);
        build(1, 1);
        for (int i=1; i<=n; i++)
            change(L[i], L[i], a[i], 1, n, 1);
        scanf("%d",&root);
        while (m--) {
            scanf("%d",&opt);
            if (opt == 1) scanf("%d",&root);
            if (opt == 2) {
                scanf("%d %d %lld",&x,&y,&val);
                cc();
            }
            if (opt == 3) {
                scanf("%d",&x);
                work();
            }
        }
    }
    
    int main () {
        init();
        close();
        return 0;
    }
  • 相关阅读:
    集合的一些操作总结
    字符串的操作
    python字典的操作总结
    python中的列表知识总结
    Python利用文件操作实现用户名的存储登入操作
    如何理解:城市的“信息化→智能化→智慧化”
    程序员必备技能-怎样快速接手一个项目
    程序员的职业规划
    只要 8 个步骤,学会这个 Docker 命令终极教程!
    使用GitLab实现CI/CD
  • 原文地址:https://www.cnblogs.com/shandongs1/p/8412648.html
Copyright © 2011-2022 走看看