• 洛谷 P4180 [BJWC2010]严格次小生成树


    洛谷 P4180 [BJWC2010]严格次小生成树

    洛谷传送门

    JDOJ 1059: 次小生成树

    JDOJ传送门

    Description

    小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是Em,严格次小生成树选择的边集是Es,那么需要满足:(value(e) 表示边e的权值) Sigma(value(e))(其中e∈Em)小于Sigma(value(e))(其中e∈Es) 这下小C蒙了,他找到了你,希望你帮他解决这个问题。

    Input

    输入文件第一行包含两个整数N和M,表示无向图的点数与边数。接下来M行,每行3个数x y z表示,点x和点y之间有一条边,边的权值为z。

    Output

    输出文件包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

    Sample Input

    5 6 1 2 1 1 3 2 2 4 3 3 5 4 3 4 3 4 5 6

    Sample Output

    11

    HINT

    数据中无向图无自环; 50% 的数据N≤2000 M≤3000; 80% 的数据N≤50000 M≤100000; 100% 的数据N≤100000 M≤300000 ,边权值非负且不超过10^9。


    题解:

    又是一道看起来简单但是并不是很简单的题。(姹紫嫣红)

    首先我们很容易通过直觉判断,次小生成树一定是通过MST最小生成树经过并不是很大的改动得到的。

    于是我们先把问题简化,这题求严格次小,那么非严格次小怎么求呢?

    根据Kruskal算法的本质:贪心。对于一条链接((u,v))但没有被选入MST的边来讲,它一定比路径((u,v))中的最长边短(也有可能等于)。那么我们只需要每次遍历没有选的边,用其替换((u,v))之间的最长边即可。

    非严格的求完了。

    严格的怎么求呢?

    与上次的思路一样,多存一个((u,v))路径上的次大值,如果最大值和边权相等,就替换次大边。

    用倍增LCA即可求解。

    常数稍大,卡卡常可过。

    代码:

    #include<cstdio>
    #include<algorithm>
    #define R register
    #define ll long long
    using namespace std;
    const int maxm=3*1e5+10;
    const int maxn=1e5+10;
    const ll INF=99824435300000;
    int n,m,cnt;
    int fa[maxn];
    bool v[maxm];
    ll dist;
    int to[maxn<<1],nxt[maxn<<1],head[maxn],val[maxn<<1],tot;
    int f[maxn][21],deep[maxn];
    ll maxx[maxn][21],minn[maxn][21];
    char *p1,*p2,buf[100000];
    #define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    inline int read()
    {
        int x=0,f=1;
        char ch=nc();
        while(ch<48||ch>57)
        {
            if(ch=='-')
                f=-1;
            ch=nc();
        }
        while(ch>=48&&ch<=57)
            x=x*10+ch-48,ch=nc();
       	return x*f;
    }
    struct edge
    {
        int x,y,z;
    }e[maxm];
    inline bool cmp(edge a,edge b)
    {
        return a.z<b.z;
    }
    inline int find(int x)
    {
        return x==fa[x]?x:fa[x]=find(fa[x]);
    }
    inline void add(int x,int y,int z)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        val[tot]=z;
        head[x]=tot;
    }
    inline void dfs(int x,int from)
    {
        deep[x]=deep[from]+1;
        f[x][0]=from;
        minn[x][0]=-INF;
        for(R int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(y==from)
                continue;
            maxx[y][0]=val[i];
            dfs(y,x);
        }
    }
    inline int Lca(int x,int y)
    {
        if(deep[x]<deep[y])
            swap(x,y);
    	for(R int i=18;i>=0;i--)
    		if(deep[f[x][i]]>=deep[y])
    			x=f[x][i];
    	if(x==y)
            return x;
    	for(R int i=18;i>=0;i--)
    		if(f[x][i]^f[y][i])
    			x=f[x][i],y=f[y][i];
    	return f[x][0];
    }
    inline ll qmax(int x,int y,ll mx)
    {
    	ll ret=-INF;
    	for(R int i=18;i>=0;i--)
    		if(deep[f[x][i]]>=deep[y])
    		{
    			if(mx!=maxx[x][i])
                    ret=max(ret,maxx[x][i]);
    			else 
                    ret=max(ret,minn[x][i]);
    			x=f[x][i];
    		}
    	return ret;
    }
    int main()
    {
        n=read();m=read();
        for(R int i=1;i<=m;i++)
            e[i].x=read(),e[i].y=read(),e[i].z=read();
        sort(e+1,e+m+1,cmp);
        for(R int i=1;i<=n;i++)
            fa[i]=i;
        for(R int i=1;i<=m;i++)
        {
            int fx=find(e[i].x);
            int fy=find(e[i].y);
            if(fx!=fy)
            {
                dist+=e[i].z;
                fa[fx]=fy;
                add(e[i].x,e[i].y,e[i].z);
                add(e[i].y,e[i].x,e[i].z);
                v[i]=1;
                cnt++;
            }
            if(cnt==n-1)
                break;
        }
        dfs(1,0);
        for(R int i=1;i<=18;i++)
    		for(R int j=1;j<=n;j++)
    		{
    			f[j][i]=f[f[j][i-1]][i-1];
    			maxx[j][i]=max(maxx[j][i-1],maxx[f[j][i-1]][i-1]);
    			minn[j][i]=max(minn[j][i-1],minn[f[j][i-1]][i-1]);
    			if(maxx[j][i-1]>maxx[f[j][i-1]][i-1])
                    minn[j][i]=max(minn[j][i],maxx[f[j][i-1]][i-1]);
                else if(maxx[j][i-1]<maxx[f[j][i-1]][i-1])
                    minn[j][i]=max(minn[j][i],maxx[j][i-1]);
    		}
        ll ans=INF;
        for(R int i=1;i<=m;i++)
    		if(!v[i])
    		{
    			int u=e[i].x;
    			int v=e[i].y;
    			ll d=e[i].z;
    			int lca=Lca(u,v);
    			ll maxu=qmax(u,lca,d);
    			ll maxv=qmax(v,lca,d);
    			ans=min(ans,dist-max(maxu,maxv)+d);
    		}
    	printf("%lld",ans);
        return 0;
    }
    
  • 相关阅读:
    绘图类
    画笔类
    创建模态,非模态对话框
    菜单类
    [WPF]程序随系统自启动
    [WPF]xml序列化以及反序列化数据
    [WPF]项目整合Metro和MaterialDesignInXamlToolkit UI框架
    [WPF]鼠标移动到Button颜色改变效果设置
    [Leetcode] 寻找数组的中心索引
    [Leetcode]在排序数组中查找元素的第一个和最后一个位置
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13724441.html
Copyright © 2020-2023  润新知