• 2022杭电多校八 1007-Darnassus(kruscal)


    题目链接:杭电多校8 - Virtual Judge

    题目:

     样例输入:

    1. 2
    2. 5
    3. 4 3 5 1 2
    4. 10
    5. 4 7 3 8 6 1 9 10 5 2

    样例输出:

    1. 7
    2. 24

    题意:给出一个排列p,把每个位置视为点,建一个无向图,i,j之间的边权为|i-j|*|pi-pj|。求这个图的最小生成树。

    先来给出最小生成树的一些性质:
    (1)一个图的最小生成树不一定唯一,但是其对应第k大边权一定是唯一的

    (2)最小生成树的最大边权一定是所有生成树的最大边权的最小值

    分析:首先我们尝试着把相邻的点之间连一条边,这样每两个相邻点之间的边权都是|pi-pj|有一棵生成树的边的最大值是小于n的,那么就等价于我们可以构造一棵最小生成树而其中所有边权均小于n,因为最小生成树的最大边权一定是所有生成树的最大边权的最小值。所以最小生成树中所有边权均小于n。那么也就是说我们只需要把所有边权小于n的边记录一下然后跑最小生成树就行。现在问题是我怎么找到边权小于n的边,根据|i-j|*|pi-pj|这道题只能用桶排,用链式前向星写一个h[i]代表权值为i的边的初始编号,记录一下每个边权出现的编号,最后直接跑一个最小生成树就可以了。注意在桶排的时候不要用vector,容易超时,而用链式前向星写会比vector快一倍多。

    下面是代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. using namespace std;
    10. const int N=5e4+10;
    11. int fu[N],a[N],mp[N];
    12. int h[N],ne[N*600],idx,u[N*600],v[N*600];
    13. struct node{
    14. int u,v,w;
    15. }p[N*600];
    16. int find(int x)
    17. {
    18. if(x!=fu[x]) fu[x]=find(fu[x]);
    19. return fu[x];
    20. }
    21. void add(int x,int y,int z)
    22. {
    23. u[idx]=x;
    24. v[idx]=y;
    25. ne[idx]=h[z];
    26. h[z]=idx++;
    27. }
    28. int main()
    29. {
    30. int T;
    31. cin>>T;
    32. while(T--)
    33. {
    34. int n;
    35. scanf("%d",&n);
    36. idx=0;
    37. for(int i=1;i<=n;i++)
    38. {
    39. fu[i]=i;h[i]=-1;
    40. scanf("%d",&a[i]);
    41. mp[a[i]]=i;
    42. }
    43. int cnt=0;
    44. for(int i=1;i<=n;i++)
    45. {
    46. int t=(int)sqrt(n);
    47. int e=min(i+t,n);
    48. for(int j=i+1;j<=e;j++)
    49. {
    50. int tt=1ll*(j-i)*abs(a[j]-a[i]);
    51. if(tt
    52. add(i,j,tt);
    53. tt=1ll*abs(mp[j]-mp[i])*(j-i);
    54. if(tt
    55. add(mp[i],mp[j],tt);
    56. }
    57. }
    58. long long ans=0;
    59. int count=0;
    60. for(int i=1;i
    61. {
    62. for(int j=h[i];j!=-1;j=ne[j])
    63. {
    64. int fx=find(u[j]),fy=find(v[j]);
    65. if(fx==fy) continue;
    66. fu[fx]=fy;
    67. count++;ans+=i;
    68. if(count==n-1) break;
    69. }
    70. if(count==n-1) break;
    71. }
    72. printf("%lld\n",ans);
    73. }
    74. return 0;
    75. }
  • 相关阅读:
    ACPI规范概览-1
    多态的定义 以及 虚函数重写(覆盖)
    Linux 权限系统
    Linux下安装cx_Oracle,连接oracle数据库
    C++11——“=default“和“=delete“函数特性
    html网页如何获取后台数据库的数据(html + ajax + php + mysql)
    如何保持电机安全运行
    SQLAlchemy详解
    探索一些常见的存储过程奥秘
    SCSS目录结构
  • 原文地址:https://blog.csdn.net/AC__dream/article/details/126308484