zoukankan      html  css  js  c++  java
  • 严格次小生成树[BJWC2010] (树链剖分,倍增,最小生成树)

    题目链接

    Solution

    有几点关键,首先,可以证明次小生成树一定是由最小生成树改变一条边而转化来.
    所以需要枚举所有非最小生成树的边((u,v)).并且找到 (u)(v) 的边中最大边和次大边.
    为什么要找次大边呢?? 因为可能最大边与要替换的边长度相等,那么这种条件生成的便不是严格的次小生成树.
    然后找到 (u,v) 之间的次大和最大边有两种方式:

    • 树链剖分+线段树维护
      剖分最小生成树,然后用线段树维护.
      此时线段树节点转移时要考虑左右节点的次大和最大的 (4) 个值.
      时间复杂度: (O(mlogn)) .
    • 树上 (st)
      与倍增求 (LCA) 的方式类似,倍增维护信息然后找 (LCA) 即可.
      时间复杂度: (O(mlogn)) .

    然后似乎还可以用 (LCT) 来做.时间复杂度也差不多.

    Code

    倍增版本:

    #include<bits/stdc++.h>
    #define N 400010
    #define M 900010
    #define INF 2147483647000000
    #define ll long long
    
    using namespace std;
    
    struct edge{
        ll u,v,d;
        ll next;
    }G[N<<1];
    ll tot=0;
    ll head[N];
    inline void addedge(ll u,ll v,ll d)
    {
        G[++tot].u=u,G[tot].v=v,G[tot].d=d,G[tot].next=head[u],head[u]=tot;
        G[++tot].u=v,G[tot].v=u,G[tot].d=d,G[tot].next=head[v],head[v]=tot;
    }
    
    ll bz[N][19];
    ll maxi[N][19];
    ll mini[N][19];
    ll deep[N];
    inline void dfs(ll u,ll fa)
    {
        bz[u][0]=fa;
        for(ll i=head[u];i;i=G[i].next)
        {
            ll v=G[i].v;
            if(v==fa)continue;
            deep[v]=deep[u]+1ll;
            maxi[v][0]=G[i].d;
            mini[v][0]=-INF;
            dfs(v,u);
        }
    }
    
    ll n;
    inline void cal()
    {
        for(ll i=1;i<=18;++i)
            for(ll j=1;j<=n;++j)
            {
                bz[j][i]=bz[bz[j][i-1]][i-1];
                maxi[j][i]=max(maxi[j][i-1],maxi[bz[j][i-1]][i-1]);
                mini[j][i]=max(mini[j][i-1],mini[bz[j][i-1]][i-1]);
                if(maxi[j][i-1]>maxi[bz[j][i-1]][i-1])mini[j][i]=max(mini[j][i],maxi[bz[j][i-1]][i-1]);
                else if(maxi[j][i-1]<maxi[bz[j][i-1]][i-1])mini[j][i]=max(mini[j][i],maxi[j][i-1]);
            }
    }
    
    inline ll LCA(ll x,ll y)
    {
        if(deep[x]<deep[y])swap(x,y);
        for(ll i=18;i>=0;--i)
            if(deep[bz[x][i]]>=deep[y])
                x=bz[x][i];
        if(x==y)return x;
        for(ll i=18;i>=0;--i)
            if(bz[x][i]^bz[y][i])
                x=bz[x][i],y=bz[y][i];
        return bz[x][0];
    }
    
    inline ll qmax(ll u,ll v,ll maxx)
    {
        ll Ans=-INF;
        for(ll i=18;i>=0;--i)
        {
            if(deep[bz[u][i]]>=deep[v])
            {
                if(maxx!=maxi[u][i])Ans=max(Ans,maxi[u][i]);
                else Ans=max(Ans,mini[u][i]);
                u=bz[u][i];
            }
        }
        return Ans;
    }
    
    inline void read(ll &x)
    {
        x=0;
        char ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+(ch^48),ch=getchar();
    }
    
    ll m;
    
    edge A[M<<1];
    
    inline bool cmp(edge x,edge y)
    {
        return x.d<y.d;
    }
    
    ll Father[N];
    inline ll Get_Father(ll x)
    {
        return (x==Father[x]) ? x : Father[x]=Get_Father(Father[x]);
    }
    
    bool B[M<<1];
    
    int main()
    {
        read(n),read(m);
        for(ll i=1;i<=m;++i)
        {
            read(A[i].u),read(A[i].v),read(A[i].d);
        }
    
        sort(A+1,A+m+1,cmp);
    
        for(ll i=1;i<=n;++i)
            Father[i]=i;
    
        ll Cnt=0ll;
        for(ll i=1;i<=m;++i)
        {
            ll Father_u=Get_Father(A[i].u);
            ll Father_v=Get_Father(A[i].v);
            if(Father_u!=Father_v)
            {
                Cnt+=A[i].d;
                Father[Father_u]=Father_v;
                addedge(A[i].u,A[i].v,A[i].d);
                B[i]=true;
            }
        }
    
        mini[1][0]=-INF;
        deep[1]=1;
        dfs(1,-1);
        cal();
    
        ll Ans=INF;
    
        for(ll i=1;i<=m;++i)
        {
            if(!B[i])
            {
                ll u=A[i].u;
                ll v=A[i].v;
                ll d=A[i].d;
                ll lca=LCA(u,v);
                ll maxu=qmax(u,lca,d);
                ll maxv=qmax(v,lca,d);
                Ans=min(Ans,Cnt-max(maxu,maxv)+d);
            }
        }
    
        printf("%lld",Ans);
    
        return 0;
    }
    

    树剖版本:

    #include<stdio.h>
    #include<algorithm>
    #include<iostream>
    #include<string.h>
    #define MAXN 100010
    #define MAXM 300010
    #define pos(l, r) ((l+r) | (l != r))
    using namespace std;
    
    struct Edge {
        int u, v, w, f, next;
        bool operator < (const Edge &A) const { return w < A.w; }
    } e[MAXM*2];
    
    struct node {
        int m1, m2;
    } t[MAXN*2];
    
    int n, m, h[MAXN], dep[MAXN], son[MAXN], w[MAXN], tot, fa[MAXN], par[MAXN], cnt, id[MAXN], top[MAXN], a[MAXN], TOT;
    long long MST, secMST = 1e15;
    inline int max(int a, int b) {
        return a > b ? a : b;
    }
    inline int secmax(int a, int b, int c, int d) {
        int tmp[4] = {a, b, c, d};
        sort(tmp, tmp+4);
        for (int i = 2; i >= 0; --i) {
            if (tmp[i] != tmp[i+1]) return tmp[i];
        }
    }
    
    void addEdge(int ui, int vi, int wi, int fi) {
        e[++tot] = (Edge) {ui, vi, wi, fi, h[ui]};
        h[ui] = tot;
    }
    
    int find(int x) {
        return fa[x] == x ? x : fa[x] = find(fa[x]);
    }
    
    void dfs(int u) {
        w[u] = 1;
        for (int i = h[u]; i; i = e[i].next) {
            if (!w[e[i].v]) {
                dep[e[i].v] = dep[u]+1;
                par[e[i].v] = u;
                a[e[i].v] = e[i].w;
                dfs(e[i].v);
                w[u] += w[e[i].v];
                if (w[son[u]] < w[e[i].v]) son[u] = e[i].v;
            }
        }
    }
    
    void init(int u, int p) {
        id[u] = ++cnt;
        top[u] = p;
        if (son[u]) init(son[u], p);
        for (int i = h[u]; i; i = e[i].next) {
            if (!top[e[i].v]) init(e[i].v, e[i].v);
        }
    }
    
    void modify(int l, int r, int x, int d, int p) {
        if (l == r) {
            t[p].m1 = d;
            t[p].m2 = 0;
        } else {
            int mid = (l+r)>>1, lc = pos(l, mid), rc = pos(mid+1, r);
            if (x <= mid) modify(l, mid, x, d, lc);
            else modify(mid+1, r, x, d, rc);
            t[p].m2 = secmax(t[lc].m1, t[lc].m2, t[rc].m1, t[rc].m2);
            t[p].m1 = max(t[lc].m1, t[rc].m1);
        }
    }
    
    node query(int l, int r, int x, int y, int p) {
        if (x <= l && r <= y) return t[p];
        int mid = (l+r)>>1, lc = pos(l, mid), rc = pos(mid+1, r);
        if (x <= mid && y > mid) {
            node t1 = query(l, mid, x, y, lc), t2 = query(mid+1, r, x, y, rc);
            return (node) {max(t1.m1, t2.m1), secmax(t1.m1, t1.m2, t2.m1, t2.m2)};
        } else if (x <= mid) return query(l, mid, x, y, lc);
        else return query(mid+1, r, x, y, rc);
    }
    
    node solve(int u, int v) {
        int pu = top[u], pv = top[v];
        node res = (node) {0, 0};
        while (pu != pv) {
            if (dep[pu] < dep[pv]) {
                swap(pu, pv);
                swap(u, v);
            }
            node tmp = query(1, n, id[pu], id[u], pos(1, n));
            res.m2 = secmax(res.m1, res.m2, tmp.m1, tmp.m2);
            res.m1 = max(res.m1, tmp.m1);
            u = par[pu];
            pu = top[u];
        }
        if (u == v) return res;
        if (dep[u] < dep[v]) swap(u, v);
        node tmp = query(1, n, id[v]+1, id[u], pos(1, n));
        res.m2 = secmax(res.m1, res.m2, tmp.m1, tmp.m2);
        res.m1 = max(res.m1, tmp.m1);
        return res;
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1, ui, vi, wi; i <= m; ++i) {
            scanf("%d%d%d", &ui, &vi, &wi);
            addEdge(ui, vi, wi, 0);
        }
        sort(e+1, e+tot+1);
        TOT = tot;
        memset(h, 0, sizeof(h));
        for (int i = 1; i <= n; ++i) fa[i] = i;
        for (int i = 1, k; i <= TOT; ++i) {
            int ux = find(e[i].u), uy = find(e[i].v);
            if (ux != uy) {
                fa[ux] = uy;
                MST += e[i].w;
                e[i].f = 1;
                e[i].next = h[e[i].u];
                h[e[i].u] = i;
                addEdge(e[i].v, e[i].u, e[i].w, 1);
                k++;
            }
            if (k == n-1) break;
        }
        dfs(1);
        init(1, 1);
        for (int i = 1; i <= n; ++i) modify(1, n, id[i], a[i], pos(1, n));
        for (int i = 1; i <= TOT; ++i) {
            if (!e[i].f) {
                node cross = solve(e[i].u, e[i].v);
                long long tmp = MST+e[i].w-(cross.m1 == e[i].w ? cross.m2 : cross.m1);
                if (tmp > MST && tmp < secMST) secMST = tmp;
            }
        }
        printf("%lld
    ", secMST);
        return 0;
    }
    
  • 相关阅读:
    javaApi Swagger配置
    java跨域配置
    applation.properties与applation.yml关于sql数据库连接配置的区别
    SpringBoot学习记录一
    Centos命令行报bash:.....:command not found的解决办法
    Referenced file contains errors (http://JAVA.sun.com/xml/ns/j2ee/web-app_2_5.xsd).
    C# 两种封装的区别
    此 ObjectContext 实例已释放,不可再用于需要连接的操作。
    .net MVC ajax传递数组
    正则表达式移除首部尾部多余字符
  • 原文地址:https://www.cnblogs.com/Kv-Stalin/p/9598247.html
Copyright © 2011-2022 走看看