习题:Power Tree(最小生成树&模型转换)
题目
思路
考虑一种类似于差分的方法
控制一个节点,我们实际上是对他的叶子进行区间加减,如果对叶子进行差分处理,那么一个节点实际上能控制\(l\)和\(r+1\)号节点,
比较明显的,如果我们要控制所有节点,那么我们一定要覆盖所有的叶子结点,也就是指我们能自由变换任意区间,很显然的,把一个节点看做一条\(l\)链接\(r+1\)的边,对其跑最小生成树即可
至于所有的方案,就是把某一个权值相同块内的所有点都扫一遍
代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
namespace IO
{
void read(int &x)
{
x=0;
int f=1;
char c=getchar();
while('0'>c||c>'9')
{
if(c=='-')
f=-1;
c=getchar();
}
while('0'<=c&&c<='9')
{
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
x*=f;
}
void read(long long &x)
{
x=0;
int f=1;
char c=getchar();
while('0'>c||c>'9')
{
if(c=='-')
f=-1;
c=getchar();
}
while('0'<=c&&c<='9')
{
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
x*=f;
}
void write(int x)
{
if(x<10)
putchar(x+'0');
else
{
write(x/10);
putchar(x%10+'0');
}
}
void write(long long x)
{
if(x<10)
putchar(x+'0');
else
{
write(x/10);
putchar(x%10+'0');
}
}
}
namespace ufs
{
int fa[200005];
void makeset(int n)
{
for(int i=1;i<=n;i++)
fa[i]=i;
}
int findset(int x)
{
if(fa[x]==x)
return x;
return fa[x]=findset(fa[x]);
}
void merge(int u,int v)
{
int a=findset(u);
int b=findset(v);
fa[a]=b;
}
}
using namespace IO;
using namespace ufs;
struct node
{
int u,v;
long long w;
int id;
friend bool operator < (const node &a,const node &b)
{
return a.w<b.w;
}
}a[200005];
int n,lena;
int cnt;
int l[200005],r[200005];
long long w[200005],mst;
vector<int> g[200005];
vector<int> ans;
void dfs(int u,int fa)
{
if(g[u].size()==1&&g[u].front()==fa)
{
l[u]=++cnt;
r[u]=cnt;
a[++lena]=(node){l[u],r[u]+1,w[u],u};
return;
}
l[u]=(1<<30);
r[u]=0;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v!=fa)
{
dfs(v,u);
l[u]=min(l[u],l[v]);
r[u]=max(r[u],r[v]);
}
}
a[++lena]=(node){l[u],r[u]+1,w[u],u};
}
int main()
{
ios::sync_with_stdio(false);
read(n);
for(int i=1;i<=n;i++)
read(w[i]);
for(int i=1,u,v;i<n;i++)
{
read(u);
read(v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
sort(a+1,a+lena+1);
makeset(n+1);
for(int i=1,j;i<=lena;i=j)
{
j=i;
while(a[j].w==a[i].w&&j<=lena)
{
if(findset(a[j].u)!=findset(a[j].v))
ans.push_back(a[j].id);
j++;
}
for(int k=i;k<j;k++)
{
if(findset(a[k].u)!=findset(a[k].v))
{
merge(a[k].u,a[k].v);
mst+=a[k].w;
}
}
}
write(mst);
putchar(' ');
write((int)ans.size());
putchar('\n');
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++)
{
write(ans[i]);
putchar(' ');
}
return 0;
}

浙公网安备 33010602011771号