• 简单题 [最小生成树, 树链剖分, 树上差分]


    简单题


    color{grey}{最初想法}

    最小生成树 构建出来, 将没加入最小生成树 的边称为 “虚边”,

    假设有一条 “虚边” 为 u,vu,v, 则 u,vu,v 在树上的路径上的边可能被替换, 称路径上的边被覆盖 .

    • 先考虑 树边 的答案怎么求,
      当一条 树边 没有被任何 “虚边” 覆盖时, 其答案显然为 10910^9,
      当一条 树边 被若干 “虚边” 覆盖时, 为了不被取代, 只能取其中最小的 “虚边” 权值 .
    • 在考虑 非树边 的答案怎么求,
      非树边 为了可能成为生成树中的边, 且权值需要尽可能大, 所以答案直接取 路径中树边的最大权值 .

    color{red}{正解部分}

    同上 .


    color{red}{实现部分}

    • 路径中树边的最大权值 可以使用 倍增 维护,
    • 路径覆盖使用 树上差分 配合 重链剖分std::multiset<int> 维护 .
    • 往上跳重链维护差分值时要注意 !!! 由于是将每条边压到这条边下面的点, 所以最后一步差分的起点位置要加 11 .
      10026100 ightarrow 26 的惨痛经历 .
    #include<bits/stdc++.h>
    #define reg register
    #define pb push_back
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 2e6 + 5;
    
    int N;
    int M;
    int num0;
    int F[maxn];
    int head[maxn];
    
    struct Edge{ int nxt, to, w, id; } edge[maxn<<1];
    
    void Add(int from, int to, int w, int id){ edge[++ num0] = (Edge){ head[from], to, w, id }; head[from] = num0; }
    
    int Find(int x){ return F[x]==x?x:F[x]=Find(F[x]); }
    
    struct EDGE{ int u, v, w, id; } E[maxn];
    
    std::multiset <int> st;
    std::multiset <int>::iterator it;
    
    std::vector <int> B[maxn];
    std::vector <EDGE> A;
    
    bool cmp_1(EDGE a, EDGE b){ return a.w < b.w; }
    
    void Krus(){
            std::sort(E+1, E+M+1, cmp_1);
            int cnt = 0;
            for(reg int i = 1; i <= N; i ++) F[i] = i;
            for(reg int i = 1; i <= M; i ++){
                    int a = Find(E[i].u), b = Find(E[i].v);
                    if(a == b) A.pb(E[i]);
                    else{ 
                            F[b] = a;
                            Add(E[i].u, E[i].v, E[i].w, E[i].id), Add(E[i].v, E[i].u, E[i].w, E[i].id);
                            if((++ cnt) >= N-1){
                                    for(reg int j = i+1; j <= M; j ++) A.pb(E[j]);
                                    return ;
                            }
                    }
            }
    }
    
    int dep[maxn];
    int Ans[maxn];
    int Fk[100005][21];
    int Mk[100005][21];
    int Fa_edge[maxn];
    
    int size[maxn];
    int max_son[maxn];
    int Fa[maxn];
    int max_w[maxn];
    
    void DFS_1(int k, int fa){ 
            dep[k] = dep[fa] + 1;
            size[k] = 1; max_son[k] = 0, max_w[k] = 0;
            Fa[k] = fa;
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == fa) continue ;
                    DFS_1(to, k); size[k] += size[to]; 
                    Fa_edge[to] = edge[i].id; 
                    if(size[to] > max_w[k]) max_w[k] = size[to], max_son[k] = to;
            }
    }
    
    int dfn_tim;
    int Mp[maxn];
    int dfn[maxn];
    int top[maxn];
    
    void DFS_2(int k, int fa){
            top[k] = fa;
            dfn[k] = ++ dfn_tim; Mp[dfn[k]] = k;
            if(max_son[k]) DFS_2(max_son[k], fa);
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(dfn[to]) continue ;
                    DFS_2(to, to);
            }
    }
    
    void Modify_P(int x, int y, int z){
            while(top[x] != top[y]){
                    if(dep[top[x]] < dep[top[y]]) std::swap(x, y);
                    B[dfn[top[x]]].pb(z), B[dfn[x]+1].pb(-z);
                    x = Fa[top[x]];
            }
            if(dfn[x] > dfn[y]) std::swap(x, y);
            B[dfn[x]+1].pb(z), B[dfn[y]+1].pb(-z);
    }
    
    void DFS_0(int k, int fa){
            for(reg int i = 1; i <= 20; i ++) Fk[k][i] = Fk[Fk[k][i-1]][i-1];
            for(reg int i = 1; i <= 20; i ++) Mk[k][i] = std::max(Mk[k][i-1], Mk[Fk[k][i-1]][i-1]);
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == fa) continue ; 
                    Fk[to][0] = k, Mk[to][0] = edge[i].w;
                    DFS_0(to, k);
            }
    }
    
    int Mca(int a, int b){
            if(dep[a] < dep[b]) std::swap(a, b);
            int s = 0;
            for(reg int i = 20; i >= 0; i --) 
                    if(dep[Fk[a][i]] >= dep[b]) s = std::max(s, Mk[a][i]), a = Fk[a][i];
            if(a == b) return s;
            for(reg int i = 20; i >= 0; i --)
                    if(Fk[a][i] != Fk[b][i]){
                            s = std::max(s, Mk[a][i]), s = std::max(s, Mk[b][i]);
                            a = Fk[a][i], b = Fk[b][i];
                    }
            s = std::max(s, Mk[a][0]); s = std::max(s, Mk[b][0]);
            return s;
    }
    
    int main(){
            N = read(), M = read();
            for(reg int i = 1; i <= M; i ++) E[i].u = read(), E[i].v = read(), E[i].w = read()+1, E[i].id = i;
            Krus();
            DFS_0(1, 0); DFS_1(1, 1); DFS_2(1, 1);
            int len = A.size();
            for(reg int i = 0; i < len; i ++){
                    int a = A[i].u, b = A[i].v;
                    Ans[A[i].id] = Mca(a, b);
                    Modify_P(a, b, A[i].w);
            }
            for(reg int i = 1; i <= N; i ++){
                    int x = Mp[i], len = B[i].size();
                    for(reg int j = 0; j < len; j ++){
                            if(B[i][j] > 0) st.insert(B[i][j]);
                            else st.erase(st.find(-B[i][j])); 
                    }
                    if(st.empty()) Ans[Fa_edge[x]] = 1e9 + 1; 
                    else Ans[Fa_edge[x]] = *st.begin();
            }
            for(reg int i = 1; i <= M; i ++) printf("%d
    ", Ans[i]-1); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! edge.w plus 1
            return 0;
    }
    
  • 相关阅读:
    C# ConfigMan.cs
    C# 反序列化JSON
    C#求数组最大值或最大值位置索引
    C#获取DataGridView数据源DataSource类型
    C#动态添加DataGridView列和行
    C# WinForm 检测文件是否被占用
    C#开源组件NPOI处理Excel导入DataTable数据至Sheet
    C# WinForm 扩展指定列宽适应DataGridView显示行数(二)
    C# WinForm 扩展指定列宽适应DataGridView显示行数
    VFP9 对 SqlServer Image字段的图片存取处理
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822470.html
Copyright © 2020-2023  润新知