题目:

样例输入:
- 2
- 5
- 4 3 5 1 2
- 10
- 4 7 3 8 6 1 9 10 5 2
样例输出:
- 7
- 24
题意:给出一个排列p,把每个位置视为点,建一个无向图,i,j之间的边权为|i-j|*|pi-pj|。求这个图的最小生成树。
先来给出最小生成树的一些性质:
(1)一个图的最小生成树不一定唯一,但是其对应第k大边权一定是唯一的
(2)最小生成树的最大边权一定是所有生成树的最大边权的最小值
分析:首先我们尝试着把相邻的点之间连一条边,这样每两个相邻点之间的边权都是|pi-pj|
下面是代码:
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- using namespace std;
- const int N=5e4+10;
- int fu[N],a[N],mp[N];
- int h[N],ne[N*600],idx,u[N*600],v[N*600];
- struct node{
- int u,v,w;
- }p[N*600];
- int find(int x)
- {
- if(x!=fu[x]) fu[x]=find(fu[x]);
- return fu[x];
- }
- void add(int x,int y,int z)
- {
- u[idx]=x;
- v[idx]=y;
- ne[idx]=h[z];
- h[z]=idx++;
- }
- int main()
- {
- int T;
- cin>>T;
- while(T--)
- {
- int n;
- scanf("%d",&n);
- idx=0;
- for(int i=1;i<=n;i++)
- {
- fu[i]=i;h[i]=-1;
- scanf("%d",&a[i]);
- mp[a[i]]=i;
- }
- int cnt=0;
- for(int i=1;i<=n;i++)
- {
- int t=(int)sqrt(n);
- int e=min(i+t,n);
- for(int j=i+1;j<=e;j++)
- {
- int tt=1ll*(j-i)*abs(a[j]-a[i]);
- if(tt
- add(i,j,tt);
- tt=1ll*abs(mp[j]-mp[i])*(j-i);
- if(tt
- add(mp[i],mp[j],tt);
- }
- }
- long long ans=0;
- int count=0;
- for(int i=1;i
- {
- for(int j=h[i];j!=-1;j=ne[j])
- {
- int fx=find(u[j]),fy=find(v[j]);
- if(fx==fy) continue;
- fu[fx]=fy;
- count++;ans+=i;
- if(count==n-1) break;
- }
- if(count==n-1) break;
- }
- printf("%lld\n",ans);
- }
- return 0;
- }
-
相关阅读:
企业电子招标采购系统源码Spring Boot + Mybatis + Redis + Layui + 前后端分离 构建企业电子招采平台之立项流程图
冲量在线出席2022第五届中国信息技术应用创新大会,同与会嘉宾分享基于信创隐私计算一体机促进数据要素市场化的解决方案
数据可视化工具 ,不会写 SQL 代码也能做数据分析
IDEA新建一个spark项目
刷爆力扣之最短无序连续子数组
[4G/5G/6G专题基础-156]: 什么是物理层信道评估
NodeJs实战-待办列表(7)-connect组件简化代码
vite3、vue 项目打包分包进阶-组件分包
Springboot+vue微信小程序的学生选课系统#毕业设计
执行java -jar命令,显示jar中没有主清单属性
-
原文地址:https://blog.csdn.net/AC__dream/article/details/126308484