题解:CF2222F Building Tree
Solution
首先进行初步转化,考虑到
于是一个朴素做法为,模拟 Kruscal 算法流程,从小往大枚举边权
-
枚举每种边权都重新建图。
-
建完图后,枚举可以建边的
(u,v) 依次建边。
解决第一个问题,可以利用分治思想,结构类似线段树。对权值序列进行分治,递归每个区间
解决第二个问题,不能等到了叶节点再在新图中加边。由于
于是,拿两个并查集维护,一个维护原图上的,一个维护新图上的。原图上的需满足可撤销,因此不可以路径压缩;新图上的起的就是 Kruscal 中并查集的作用。由于分治和启发式合并,总时间复杂度为
Code
码风清纯。
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <stack>
using namespace std;
typedef long long LL;
int read()
{
char c=getchar();
int f=1,x=0;
while(c<'0'||c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=(x<<1)+(x<<3)+(c^'0');
c=getchar();
}
return x*f;
}
void print(LL x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9) print(x/10);
putchar(x%10+'0');
}
const int N=3e5+5;
int T,n,m,q;
bool a[N];
vector<pair<int,int>> e[N];
LL ans;
struct dsu
{
int fa[N];
void init(){for(int i=1;i<=n;i++) fa[i]=i;}
int findfa(int x)
{
if(x==fa[x]) return x;
return fa[x]=findfa(fa[x]);
}
void merge(int x,int y,int w)
{
x=findfa(x),y=findfa(y);
if(x==y) return;
ans+=w;
fa[y]=x;
}
}d;
struct dsu2
{
int fa[N],sz[N],g[N];
void init(){for(int i=1;i<=n;i++) fa[i]=i,sz[i]=1,g[i]={a[i]?i:0};}
int findfa(int x)
{
if(x==fa[x]) return x;
return findfa(fa[x]);
}
int merge(int x,int y,int w)
{
x=findfa(x),y=findfa(y);
if(x==y) return 0;
if(g[x]&&g[y]) d.merge(g[x],g[y],w);
if(sz[x]<sz[y]) swap(x,y);
fa[y]=x;
sz[x]+=sz[y];
if(!g[x]&&g[y]) g[x]=g[y];
return y;
}
void del(int x)
{
if(g[fa[x]]==g[x]) g[fa[x]]=0;
sz[fa[x]]-=sz[x];
fa[x]=x;
}
}d2;
void solve(int l,int r)
{
if(l>=r) return;
int mid=(l+r)>>1;
stack<int> s;
for(int i=mid+1;i<=r;i++)
{
for(auto it=e[i].begin();it!=e[i].end();it++)
{
int u=(*it).first,v=(*it).second,x=d2.merge(u,v,l);
if(x) s.push(x);
}
}
solve(l,mid);
while(s.size())
{
int u=s.top();
d2.del(u);
s.pop();
}
for(int i=l;i<=mid;i++)
{
for(auto it=e[i].begin();it!=e[i].end();it++)
{
int u=(*it).first,v=(*it).second,x=d2.merge(u,v,mid+1);
if(x) s.push(x);
}
}
solve(mid+1,r);
while(s.size())
{
int u=s.top();
d2.del(u);
s.pop();
}
}
int main()
{
T=read();
while(T--)
{
n=read();
m=read();
q=read();
for(int i=0;i<=m;i++) e[i].clear();
for(int i=1;i<=m;i++)
{
int u,v,w;
u=read();
v=read();
w=read();
e[w].push_back(make_pair(u,v));
}
for(int i=1;i<=n;i++) a[i]=false;
for(int i=1;i<=q;i++)
{
int x=read();
a[x]=true;
}
d.init();
d2.init();
ans=0;
solve(0,m);
int cnt=0;
for(int i=1;i<=n;i++)
if(a[i]) cnt+=(d.fa[i]==i);
if(cnt>1) puts("-1");
else print(ans),putchar('\n');
}
return 0;
}