zoukankan      html  css  js  c++  java
  • XJOI 3629 非严格次小生成树(pqq的礼物)

    题目描述:

    有一天,pqq准备去给×i×准备礼物,他有一些礼品准备包装一下,他用线将这些礼物连在一起,不同的礼物因为风格不同所以连接它们需要不同价值的线。风格差异越大,价格越大(所以两个礼物之间只有一种连接价格),当然有些礼物实在太不友好,所以有些礼物无法相连。pqq打算把所有礼物打包在一起,他不准备花太多钱,但更不想花最少的钱(免得被拒绝)。所以他想知道第二便宜的包装方案(可重复,pqq会认为这是天命并直接选用最小代价来包装礼物),同时,他还想知道最小的包装代价以向×i×进行炫耀。但是由于pqq不够心灵手巧,所以他准备找你来帮他计算答案。

     

    输入格式:

     两个数nm表示有n个礼物,有m对礼物可以相连1n,m2105

     接下来的m行每行三个数a,b,c,表示a礼物和b礼物可以用c的价值相连 , 1a,bn,1c106

     

    输出格式:

    输出一行,包含两个数,分别是最小代价和次小代价

     

    样例输入:

    5 10
    1 2 1
    2 3 2
    3 4 3
    4 5 4
    1 3 5
    1 4 6
    1 5 7
    2 4 8
    2 5 9
    3 5 10

     

    样例输出:

    10 11

    瞎扯:我其实很好奇XiX是谁啊┐(´∀`)┌

    题解:其实非严格次小生成树的思路还是很好理解的
    首先是什么是非严格次小生成树
    就是树边和可以等于和大于最小生成树的另一颗生成树
    假设现在要把一条非树边(u,v,c)加入最小生成树,想必要去掉一条原生成树中u->v的边,显然去掉最大边效果是最好的
    所以在最小生成树上跑一个倍增DP,d[i][j]表示j的2^i次祖先到j的路径中最大的值
    显然可以跟跳lca一样的在logn的跳出u->v路径上的最大值,当然树链剖分也是可以搞这个东西的,但是再写一颗线段树还享受lognlogn的复杂度
    emmmm,何必呢……
    如果能跳出这个值,我们只要枚举每一条非树边,就可以在nlogn的复杂度里跳出非严格次小生成树,然后就A掉了

    代码如下:
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define pii pair<int,int>
    #define mp make_pair
    #define int long long
    using namespace std;
    
    int fa[200010],vis[200010],deep[200010],n,m,f[19][250010],d[19][250010],ans1,ans2;
    vector<pii> g[200010];
    struct line
    {
        int from,to,cost;
    }l[200010];
    
    int cmp(line a,line b)
    {
        return a.cost<b.cost;
    }
    
    void init()
    {
        for(int i=1;i<=n;i++)
        {
            fa[i]=i;
        }
    }
    
    int find(int x)
    {
        if(fa[x]==x) return x;
        return fa[x]=find(fa[x]);
    }
    
    void unity(int t,int x,int y,int c)
    {
        int fx=find(x);
        int fy=find(y);
        if(fx==fy) return ;
        fa[fx]=fy;
        ans1+=c;
        vis[t]=1;
        g[x].push_back(mp(y,c));
        g[y].push_back(mp(x,c));
    }
    
    void dfs(int now,int ff,int dist,int dep)
    {
        d[0][now]=dist;
        f[0][now]=ff;
        deep[now]=dep;
        for(int i=1;i<=18;i++)
        {
            f[i][now]=f[i-1][f[i-1][now]];
        }
        for(int i=1;i<=18;i++)
        {
            d[i][now]=max(d[i-1][now],d[i-1][f[i-1][now]]);
        }
        for(int i=0;i<g[now].size();i++)
        {
            if(g[now][i].first==ff) continue;
            dfs(g[now][i].first,now,g[now][i].second,dep+1);
        }
    }
    
    int get(int u,int v)
    {
        int x=u,y=v;
        if(deep[x]<deep[y]) swap(x,y);
        int di=0;
        for(int i=18;i>=0;i--)
        {
            if(deep[f[i][x]]>=deep[y])
            {
                di=max(di,d[i][x]);
                x=f[i][x];
            }
        }
        if(x==y) return di;
        for(int i=18;i>=0;i--)
        {
            if(f[i][x]!=f[i][y])
            {
                di=max(max(d[i][x],d[i][y]),di);
                x=f[i][x];
                y=f[i][y];
            }
        }
        return max(di,max(d[0][x],d[0][y]));
    }
    
    signed main()
    {
        scanf("%lld%lld",&n,&m);
        init();
        for(int i=1;i<=m;i++)
        {
            scanf("%lld%lld%lld",&l[i].from,&l[i].to,&l[i].cost);
        }
        sort(l+1,l+m+1,cmp);
        for(int i=1;i<=m;i++)
        {
            unity(i,l[i].from,l[i].to,l[i].cost);
        }
        dfs(1,0,0,1);
        ans2=1e16;
        for(int i=1;i<=m;i++)
        {
            if(!vis[i])
            {
                ans2=min(ans2,ans1+l[i].cost-get(l[i].from,l[i].to));
            }
        }
        printf("%lld %lld
    ",ans1,ans2);
    }
    
    
    
     
  • 相关阅读:
    (Redis基础教程之十) 如何在Redis中运行事务
    (Python基础教程之十三)Python中使用httplib2 – HTTP GET和POST示例
    (Redis基础教程之六)如何使用Redis中的List
    (Redis基础教程之九) 如何在Redis中使用Sorted Sets
    (Python基础教程之十九)Python优先级队列示例
    (Python基础教程之十八)Python字典交集–比较两个字典
    (Python基础教程之十七)Python OrderedDict –有序字典
    Heap_Sort
    Quick_Sort
    Merge_Sort
  • 原文地址:https://www.cnblogs.com/stxy-ferryman/p/9325557.html
Copyright © 2011-2022 走看看