1 条题解
-
0
自动搬运
来自洛谷,原作者为

Khassar
**搬运于
2025-08-24 21:39:14,当前版本为作者最后更新于2017-07-21 20:36:32,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
/* 题目大意为:在只能从点权大的点到点权小的点(可以相等)的情况下,从1点出发建立一棵尽可能有更多点的最小生成树
显然我们不能直接求最小生成树,因为有些点应为高度原因无法到达。
为保证我们只会由高到低,我们就只建立由高向低的单向边即可。
对于建立出来的图A,由1点开始宽搜,将扩展到的点和边加入一个新图B,所有扩展到的点便是能到达的最多点。
我们再在这个新图上跑Kruskal求最小生成树,求得最短距离。
对于排序部分,为保证有尽可能多的点在最小生成树里,我们按终点的高度为第一关键字从大到小排序,边长为第二关键字从小到大排序;
这样就能保证拓展的点最多,进而再用最小生成树求最短距离。
*/
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<cstdlib> #include<string> #include<queue> #include<map> #include<vector> #define ll long long #define R register #define Rf(a,b,c) for(R int (a)=(b);(a)<=(c);++(a)) #define Tf(a,b,c) for(R int (a)=(b);(a)>=(c);--(a)) using namespace std; const int N=2000000+5,M=100000+5; ll n,m,tot,ans,num,sum,cnt,ql,qr; struct it{ ll u,v,w;//新图 }; struct node { ll to,nx,val;//初始图(链式前向星) }; it a[N];node b[N]; ll fa[M],h[M],head[M],q[M]; bool vis[M]; inline ll read()//读入优化 { ll x=0,f=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x*=10;x+=(ch-'0');ch=getchar();} return x*f; } bool cmp1(it x,it y) { //比较函数,以终点的高度为第一关键字从大到小排序,边长为第二关键字从小到大排序 if(h[x.v]!=h[y.v]) return h[x.v]>h[y.v]; return x.w<y.w; } inline ll find(ll x) {//并查集找父亲 if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } inline void add(int u,int v,int c) {//链式前向星加边 b[++num].to=v; b[num].nx=head[u]; head[u]=num; b[num].val=c; } void bfs(){//宽搜,拓展可到达的点,建新图 q[++qr]=1;vis[1]=1; while(ql<qr) { int now=q[++ql]; for(int i=head[now];i;i=b[i].nx) { a[++cnt].u=now;a[cnt].v=b[i].to;a[cnt].w=b[i].val;//建立新图的边 if(!vis[b[i].to]) { vis[b[i].to]=1;sum++;//sum计数器计可到达的点 q[++qr]=(b[i].to); } } } } int main() { // freopen("steep.in","r",stdin); // freopen("steep.out","w",stdout); n=read();m=read();//读入数据 Rf(i,1,n) h[i]=read(),fa[i]=i; Rf(i,1,m) { R int u=read(),v=read(),c=read(); if(h[u]>=h[v]) add(u,v,c);//根据边两边的点的高度,建立一条由高到低的单向边 if(h[u]<=h[v]) add(v,u,c);//当高度相等时会建两条边 } bfs();//广搜拓展点 sort(a+1,a+1+cnt,cmp1);//对新图的点跑Kruskal求最小生成树 Rf(i,1,cnt) { R int rx=find(a[i].u),ry=find(a[i].v); if(rx!=ry) { fa[rx]=ry;ans+=a[i].w;//求最短距离 } } printf("%lld %lld",sum+1,ans);//sum+1,还有初始的1点可到 return 0; }
- 1
信息
- ID
- 1613
- 时间
- 5000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者