首页 > 其他分享 >CF1108F MST Unification

CF1108F MST Unification

时间:2022-11-16 11:25:53浏览次数:64  
标签:point int ll MST CF1108F read Unification ans bz

CF1108F MST Unification

前言

神说,你需要一颗最小生成树,于是你求出了最小生成树。

神又说,你这生成树不唯一啊,快去改改,于是就有了这篇题解

思路

P4180 [BJWC2010] 严格次小生成树 ,先算出最小生成树。

由于要保证树唯一,考虑怎么才可以让其唯一。

回顾 克鲁斯卡尔 算法可以发现,如果有相同长度的边,连接的两个相同的点集,那么这两个边都可选,这就是最小生成树多解的原因。

于是就有了两种方式:

方一

引用自博客 大佬:良心WA题人

我们考虑将长度相同的边一起处理,具体如下:

  1. 先将长度相同的边给找出来
  2. 记录在没有连接这些边的情况下,边两端点集不同的边的边数为 \(cnt\)
  3. 从前到后连边,如果可以连接则 cnt--

最后 \(ans=\sum cnt\)

方二

直接考虑生成树后树上倍增,对于一条非树边,求得其两端点之间的简单路径上边权的最大值,若与该非树边边权相等,则 ans++

CODE
// #pragma GCC optimize("Ofast")
// #pragma GCC optimize("inline")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
typedef long double ld;
const ll maxn=2e5+2;
 
inline ll read_int(){
	ll a=0;bool f=0;char g=getchar();
	while(g<'0'||g>'9') {if(g=='-') f=1;g=getchar();}
	while('0'<=g&&g<='9') a=a*10+g-'0',g=getchar();
	return f ? -a : a;
}
 
inline void write(ll a,bool f=1){
	char lin[40];ll top=0;
	if(a<0) a=-a,putchar('-');
	while(a) lin[++top]=a%10+'0',a/=10;
	if(!top) lin[++top]='0';
	while(top) putchar(lin[top--]);
	if(f) putchar('\n');
}
 
struct SJ{int f,t,v;}sj[maxn];int cnt;
bool operator < (const SJ a,const SJ b){return a.v<b.v;}
 
struct E{
    int t,n;
    ll v;
}edge[maxn*2];
int l,head[maxn];
 
struct BCJ{
    int bcj[maxn];
    inline void neww(int n){
        for(int i=1;i<=n;i++) bcj[i]=i;
    }
    inline int find(int s){return (s==bcj[s] ? s : (bcj[s]=find(bcj[s])));}
    inline void add(int a,int  b){
        bcj[find(a)]=find(b);
    }
    inline bool link(int a,int b){return find(a)==find(b);}
}bcj;
 
int n,m;
 
ll bz[maxn][21],point[maxn][21],dep[maxn];
inline void dfs(int s,int f,int W){
    bz[s][0]=W,point[s][0]=f;
    dep[s]=dep[f]+1;
    for(int i=1;i<=20;i++){
        bz[s][i]=max(bz[s][i-1],bz[point[s][i-1]][i-1]);
        point[s][i]=point[point[s][i-1]][i-1];
    }
    for(int i=head[s];i;i=edge[i].n){
        int t=edge[i].t;
        if(t==f) continue;
        dfs(t,s,edge[i].v);
    }
}
 
inline int upto(ll &ans,int s,int C){
    for(int i=20;~i;i--){
        if((1<<i)&C) ans=max(ans,bz[s][i]),s=point[s][i];
    }
    return s;
}
 
inline int LCA_max(int a,int b){
    ll ans=0;
    if(dep[a]>dep[b]) swap(a,b);
    b=upto(ans,b,dep[b]-dep[a]);
    if(a==b) return ans;
    for(int i=20;~i;i--){
        if(point[a][i]==point[b][i]) continue;
        ans=max(ans,max(bz[a][i],bz[b][i]));
        a=point[a][i],b=point[b][i];
    }
    return max(ans,max(bz[a][0],bz[b][0]));
}
 
inline void read(){
    n=read_int(),m=read_int();
    for(int i=1;i<=m;i++){
        sj[i].f=read_int(),sj[i].t=read_int(),sj[i].v=read_int();
        if(sj[i].f==sj[i].t){i--,m--;}
    }
    bcj.neww(n);
    sort(sj+1,sj+1+m);
    for(int i=1;i<=m;i++){
        if(bcj.link(sj[i].f,sj[i].t)){sj[++cnt]=sj[i];continue;}
        l++,edge[l]=(E){sj[i].t,head[sj[i].f],sj[i].v},head[sj[i].f]=l;
        l++,edge[l]=(E){sj[i].f,head[sj[i].t],sj[i].v},head[sj[i].t]=l;
        bcj.add(sj[i].f,sj[i].t);
    }
    dfs(1,1,0);
    int ans=0;
    for(int i=1;i<=cnt;i++){
        ans+=(LCA_max(sj[i].f,sj[i].t)==sj[i].v);
    }
    write(ans);
}
 
int main (){
    // freopen(".in","r",stdin);
    read();
    // while(1) getchar();
}

标签:point,int,ll,MST,CF1108F,read,Unification,ans,bz
From: https://www.cnblogs.com/LQX-OI/p/16895240.html

相关文章

  • Linux vmstat命令实战详解
    vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。这个命令是我查看Linux/Unix......
  • CF1656F Parametric MST
    给定一张\(n\)个点的无向完全图\(K_n(t)\),点\(i\)和点\(j\)之间的边的边权\(w_{i,j}(t)\)为\(a_i\timesa_j+t\times(a_i+a_j)\),其中\(t\)为任意实数。定......
  • Camstar获取回参
     publicstaticboolSplitQty(stringUsername,stringPassword,stringContainer,intsplitQty,intplateQty,refList<string>childList,refstringMsg)......
  • 关闭显示远程桌面mstsc顶部(侧面)连接栏
    在进行mstsc远程桌面连接电脑或者虚拟机的时候,总是会出现一个连接栏。虽然点左边的图钉可以自动隐藏,但是每次鼠标滑到上面的时候,还是会冒出来,这个就有点闹心了。查了下相......
  • 在使用mstsc远程连接Windows 2016 Server服务器时报错“出现身份验证错误 要求的函数
    问题描述:在使用mstsc远程连接Windows2016Server服务器时报错“出现身份验证错误要求的函数不受支持……”,如下所示:解决方案:在windows2016server服务器远程设置上不勾......
  • activemq-cpp getCMSType类型判断是否有效
    场景   CMS消息类型有BytesMessage,TextMessage,MapMessage,StreamMessage,是否可以通过getCMSType知道是哪一个类型的消息?答案    不行,依然需要通过constcms::By......
  • C#中Trim()、TrimStart()、TrimEnd()的用法
    https://www.cnblogs.com/carekee/articles/2094731.htmlC#中Trim()、TrimStart()、TrimEnd()的用法:   这三个方法用于删除字符串头尾出现的某些字符。Trim()删除字......
  • 【XSY2485】MST(最小生成树+倍增lca+并查集)
    题面Description给定一个\(n\)个点\(m\)条边的连通图,保证没有自环和重边。对于每条边求出,在其他边权值不变的情况下,它能取的最大权值,使得这条边在连通图的所有最小生成......
  • 【CF888G】Xor-MST(01Trie,最小生成树)
    看到异或最值要么是线性基要么是01Trie。线性基显然可以排除。那么先把所有的\(a_i\)插入01Trie内。然后发现对于任意两个数\(a_i\)和\(a_j\):你发现它们在\(......
  • Linux vmstat命令实战详解
    vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。这个命令是我查看Linux/Unix......