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

简单题


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;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822470.html