• cf 911F 树的直径+贪心


    $des$ 

    给定一棵 n 个节点的树,你可以进行 n ? 1 次操作,每次操作步骤如下:
    选择 u,v 两个度数为 1 的节点。
    将 u,v 之间的距离加到 ans 上。
    将 u 从树上删除。
    求一个操作序列使得 ans 最大。

    $sol$

    先把直径拿出来,将直径外的点一个一个的和直径中的某一个端点配对并删掉。最
    后再将直径删掉。这样就是对的。
    如果当前直径外已经没有点了,那么显然只能将直径的端点删掉。否则一定不会去
    删直径的端点。
    因为先删一个直径外的点再删直径端点一定是不劣于先删直径端点再删这个直径外
    的点的。

    $code$

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define gc getchar()
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    
    }
    
    #define LL long long
    #define Rep(i, a, b) for(int i = a; i <= b; i ++)
    #define E exit(0)
    
    const int N = 2e5 + 10;
    
    int disa[N], disb[N], fa[N], A[N], topp[N], size[N], son[N], deep[N], sonjs[N];
    bool Be_calc[N], vis[N], is_chain[N];
    int Cut[N], js;
    
    struct Node {int v, nxt;} G[N << 1];
    int head[N], cnt;
    
    int n, One, Tow;
    
    void Link(int u, int v) {
        G[++ cnt].v = v; G[cnt].nxt = head[u]; head[u] = cnt;
    }
    
    int Bfs(int start, int dis[]) {
        queue <int> Q;
        memset(vis, 0, sizeof vis);
        dis[start] = 0;
        vis[start] = 1;
        Q.push(start);
        while(!Q.empty()) {
            int topp = Q.front();
            Q.pop();
            for(int i = head[topp]; ~ i; i = G[i].nxt) {
                int v = G[i].v;
                if(!vis[v]) {
                    dis[v] = dis[topp] + 1;
                    vis[v] = 1;
                    Q.push(v);
                }
            }
        }
        int ret, retdis = -1;
        Rep(i, 1, n) if(dis[i] > retdis) ret = i, retdis = dis[i];
        return ret;
    }
    
    void Dfs1(int u, int f_, int dep) {
        fa[u] = f_, deep[u] = dep; size[u] = 1;
        for(int i = head[u]; ~ i; i = G[i].nxt) {
            int v = G[i].v;
            if(v == f_) continue;
            sonjs[u] ++;
            Dfs1(v, u, dep + 1);
            size[u] += size[v];
            if(size[v] > size[son[u]]) son[u] = v;
        }
    }
    
    void Dfs2(int u, int tp) {
        topp[u] = tp;
        if(!son[u]) {
            Cut[++ js] = u;
            return ;
        }
        Dfs2(son[u], tp);
        for(int i = head[u]; ~ i; i = G[i].nxt) {
            int v = G[i].v;
            if(v != fa[u] && v != son[u]) Dfs2(v, v);
        }
    }
    
    inline int Lca(int x, int y) {
        int tpx = topp[x], tpy = topp[y];
        while(tpx != tpy) {
            if(deep[tpx] < deep[tpy]) swap(x, y), swap(tpx, tpy);
            x = fa[tpx], tpx = topp[x];
        }
        if(deep[x] < deep[y]) swap(x, y);
        return y;
    }
    
    void Find_chain() {
        int lca = Lca(One,Tow);
        int tmp1 = One, tmp2 = Tow;
        while(tmp1 != lca) {
            is_chain[tmp1] = 1;
            tmp1 = fa[tmp1];
        }
        while(tmp2 != lca) {
            is_chain[tmp2] = 1;
            tmp2 = fa[tmp2];
        }
        is_chain[lca] = 1;
    }
    
    int o_1[N], o_2[N], o_3[N], tot;
    
    int main() {
        n = read();
        Rep(i, 1, n) head[i] = -1;
        Rep(i, 1, n - 1) {
            int u = read(), v = read(); Link(u, v), Link(v, u);
        }
        
        One = Bfs(1, disa);
        Tow = Bfs(One, disa);
        Bfs(Tow, disb);
        Dfs1(One, 0, 1);
        Dfs2(One, One);
        Find_chain();
    
        LL Answer = 0;
        Rep(i, 1, js) {
            if(is_chain[Cut[i]] || Be_calc[Cut[i]]) continue;
            int now = Cut[i];
            
            while(!Be_calc[now] && !is_chain[now] && !sonjs[now]) {
                if(disa[now] > disb[now]) {
                    o_1[++ tot] = One, o_2[tot] = now, o_3[tot] = now;
                    Answer += disa[now];
                } else {
                    o_1[++ tot] = Tow, o_2[tot] = now, o_3[tot] = now;
                    Answer += disb[now];
                }
                Be_calc[now] = 1;
                now = fa[now];
                sonjs[now] --;
            }
        }
        
        int lca = Lca(One, Tow);
        
        while(One != lca) {
            o_1[++ tot] = One, o_2[tot] = Tow, o_3[tot] = One;
            Answer += disb[One];
            One = fa[One];
        }
        while(Tow != lca) {
            o_1[++ tot] = Tow, o_2[tot] = lca, o_3[tot] = Tow;
            Answer += (deep[Tow] - deep[lca]);
            Tow = fa[Tow];
        }
        
        cout << Answer << "
    ";
        Rep(i, 1, tot) {
            cout << o_1[i] << " " << o_2[i] << " " << o_3[i] << "
    ";
        }
        return 0;
    }
  • 相关阅读:
    Flink流处理(一)- 状态流处理简介
    YARN High Availablity
    把数组转换成sql中能使用的字符串
    StringUtils中 isNotEmpty 和isNotBlank的区别
    SQL的四种连接-左外连接、右外连接、内连接、全连接
    JS判断输入是否为整数的正则表达式
    Java构造和解析Json数据的两种方法详解二
    JSON详解
    Java构造和解析Json数据的两种方法详解一
    详细讲解JAVA中的IO流
  • 原文地址:https://www.cnblogs.com/shandongs1/p/9770887.html
Copyright © 2020-2023  润新知