题目描述

一个人有很多的影子,新的旧的,他们不断消失重来。学者的影子在他苍白色的精神图景里成为了$n$个黑色的点,他们伸长的触手交叉形成了一颗黑色的树。假使每个影子点拥有一个权值$d_i$,黑色的树边也有一个权值$w_i$,对于一条黑色树的路径,令路径上所有影子点权值$d_i$的最小值为${min}_d$,路径上所有树边权值$w_i$的总和为$sum_w$,则该条路径的总权值为${min}_d\times sum_w$。路径的起点和终点可以是黑色树中的任意影子点,且路径中不能出现重复的影子点。
现在学者需要知道这棵黑色树里所有路径总权值中的最大值为多少


输入格式

第一行输入一个整数$T$,表示数据组数
每组数据第一行一个正整数$n$,表示影子点总数
之后$n$个整数,表示每个影子点的权值
之后$n-1$行,每行三个整数$u,v,w$表示一条连接$u,v$且权值为$w$的树边。数据保证不会出现重边,且一定构成树结构


输出格式

一共$T$行,表示当前这组数据的答案


样例

样例输入:

1
3
1 2 3
1 2 1
1 3 2

样例输出:

3


数据范围与提示

样例解释:

总权值最大的路径是$2\rightarrow 1\rightarrow 3$,${min}_d$为$min(1,2,3)=1$,${sum}_w$为$sum(1,2)=3$,因此答案为$1\times 3=3$。

数据范围:

对于$100\%$的数据$1\leqslant T\leqslant 10,1\leqslant n\leqslant {10}^5,1\leqslant d_i\leqslant {10}^9,1\leqslant u,v\leqslant n,1\leqslant w_i\leqslant {10}^9$
其中$35\%$的数据$1\leqslant n\leqslant 100$
其中最多有$50\%$的数据保证${10}^4\leqslant n\leqslant {10}^5$


题解

再一次没有打正解,显然正解是点分治。

然而我用的是比较玄学的并查集。

首先,将所有的点权从大到小排序,于将当前点和与其相连的所有点依次合并到一个集合中。

并查集维护当前集合中的最长路径长度和对应的两个端点。

保证当前这个点是并查集中最大的点,这样它肯定对$min_d$没有贡献。

那么,合并两个集合后集合的最长路分为两种情况:

  $\alpha.$其中一个集合的最长路。

  $\beta.$两个集合的最长路的端点相互连接。

这里就需要用到$LCA$了。

每次合并并查集之后用当前点的权值乘以最长路的总长度来更新最优结果即可。即使这个点不在当前合并后的集合的最长路上也是没有问题的,因为如果这样的话,必然已经在之前得到了对应的结果,这次合并不会对最终结果产生影响。

时间复杂度:$\Theta(n\log n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. struct rec{int nxt,to,w;}e[200001];
  4. int head[100001],cnt;
  5. int n;
  6. int f[100001],lft[100001],rht[100001],rk[100001];
  7. int fa[100001][21],depth[100001];
  8. long long dis[100001],len[100001];
  9. pair<int,int> d[100001];
  10. long long ans;
  11. void pre_work()
  12. {
  13. memset(len,0,sizeof(len));
  14. memset(head,0,sizeof(head));
  15. memset(depth,0,sizeof(depth));
  16. ans=cnt=0;
  17. for(int i=1;i<=n;i++)f[i]=lft[i]=rht[i]=i;
  18. }
  19. void add(int x,int y,int w)
  20. {
  21. e[++cnt].nxt=head[x];
  22. e[cnt].to=y;
  23. e[cnt].w=w;
  24. head[x]=cnt;
  25. }
  26. int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
  27. void dfs(int x)
  28. {
  29. for(int i=head[x];i;i=e[i].nxt)
  30. {
  31. if(depth[e[i].to])continue;
  32. depth[e[i].to]=depth[x]+1;
  33. fa[e[i].to][0]=x;
  34. for(int j=1;j<=20;j++)
  35. fa[e[i].to][j]=fa[fa[e[i].to][j-1]][j-1];
  36. dis[e[i].to]=dis[x]+e[i].w;
  37. dfs(e[i].to);
  38. }
  39. }
  40. int LCA(int x,int y)
  41. {
  42. int minn=1<<30;
  43. if(depth[x]>depth[y])swap(x,y);
  44. for(int i=20;~i;i--)
  45. if(depth[fa[y][i]]>=depth[x])
  46. y=fa[y][i];
  47. if(x==y)return x;
  48. for(int i=20;~i;i--)
  49. if(fa[x][i]!=fa[y][i])
  50. {
  51. x=fa[x][i];
  52. y=fa[y][i];
  53. }
  54. return fa[x][0];
  55. }
  56. long long get_dis(int x,int y){return dis[x]+dis[y]-(dis[LCA(x,y)]<<1);}
  57. int main()
  58. {
  59. int T;scanf("%d",&T);
  60. while(T--)
  61. {
  62. scanf("%d",&n);
  63. pre_work();
  64. for(int i=1;i<=n;i++)
  65. {
  66. int x;scanf("%d",&x);
  67. d[i]=make_pair(x,i);
  68. }
  69. sort(d+1,d+n+1,greater<pair<int,int> >());
  70. for(int i=1;i<n;i++)
  71. {
  72. int u,v,w;
  73. scanf("%d%d%d",&u,&v,&w);
  74. add(u,v,w);
  75. add(v,u,w);
  76. }
  77. depth[1]=1;
  78. dfs(1);
  79. for(int i=1;i<=n;i++)rk[d[i].second]=i;
  80. for(int i=1;i<=n;i++)
  81. {
  82. for(int j=head[d[i].second];j;j=e[j].nxt)
  83. {
  84. int to=find(e[j].to);
  85. if(rk[d[i].second]<rk[to])continue;
  86. len[0]=len[d[i].second],lft[0]=lft[d[i].second],rht[0]=rht[d[i].second];
  87. if(len[to]>len[0]){len[0]=len[to];lft[0]=lft[to];rht[0]=rht[to];}
  88. if((dis[0]=get_dis(lft[d[i].second],lft[to]))>len[0]){len[0]=dis[0];lft[0]=lft[d[i].second];rht[0]=lft[to];}
  89. if((dis[0]=get_dis(rht[d[i].second],rht[to]))>len[0]){len[0]=dis[0];lft[0]=rht[d[i].second];rht[0]=rht[to];}
  90. if((dis[0]=get_dis(lft[d[i].second],rht[to]))>len[0]){len[0]=dis[0];lft[0]=lft[d[i].second];rht[0]=rht[to];}
  91. if((dis[0]=get_dis(rht[d[i].second],lft[to]))>len[0]){len[0]=dis[0];lft[0]=rht[d[i].second];rht[0]=lft[to];}
  92. f[to]=d[i].second;lft[d[i].second]=lft[0];rht[d[i].second]=rht[0];len[d[i].second]=len[0];
  93. }
  94. ans=max(ans,len[d[i].second]*d[i].first);
  95. }
  96. printf("%lld\n",ans);
  97. }
  98. return 0;
  99. }

rp++

[CSP-S模拟测试]:影子(并查集+LCA)的更多相关文章

  1. hdu 2874 Connections between cities (并查集+LCA)

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

  2. hdu6074[并查集+LCA+思维] 2017多校4

    看了标答感觉思路清晰了许多,用并查集来维护全联通块的点数和边权和. 用另一个up[]数组(也是并查集)来保证每条边不会被重复附权值,这样我们只要将询问按权值从小到大排序,一定能的到最小的边权和与联通块 ...

  3. [CSP-S模拟测试]:Dash Speed(线段树+并查集+LCA)

    题目描述 比特山是比特镇的飙车圣地.在比特山上一共有$n$个广场,编号依次为$1$到$n$,这些广场之间通过$n−1$条双向车道直接或间接地连接在一起,形成了一棵树的结构. 因为每条车道的修建时间以及 ...

  4. Gym 100814C Connecting Graph 并查集+LCA

    Description standard input/output Statements Alex is known to be very clever, but Walter does not be ...

  5. Network-POJ3694并查集+LCA

    Network Time Limit: 5000MS   Memory Limit: 65536K       Description A network administrator manages ...

  6. [并查集+LCA USACO18OPEN ] Disruption

    https://www.luogu.org/problemnew/show/P4374 一看这道题就是一个妙题,然后题解什么树链剖分...珂朵莉树... 还不如并查集来的实在!我们知道并查集本来就是路 ...

  7. Mobile Phone Network CodeForces - 1023F(并查集lca+修改环)

    题意: 就是有几个点,你掌控了几条路,你的商业对手也掌控了几条路,然后你想让游客都把你的所有路都走完,那么你就有钱了,但你又想挣的钱最多,真是的过分..哈哈 游客肯定要对比一下你的对手的路 看看那个便 ...

  8. HDU6074 Phone Call (并查集 LCA)

    Phone Call Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Tota ...

  9. 习题:过路费(kruskal+并查集+LCA)

    过路费  [问题描述]在某个遥远的国家里,有 n 个城市.编号为 1,2,3,…,n.这个国家的政府修 建了 m 条双向道路,每条道路连接着两个城市.政府规定从城市 S 到城市 T 需 要收取的过路费 ...

随机推荐

  1. VB.NET导出Excel 轻松实现Excel的服务器与客户端交换 服务器不安装Office

    说来VB.Net这个也是之前的一个项目中用到的.今天拿来总结下用途,项目需求,不让在服务器安装Office办公软件.这个也是煞费了一顿. 主要的思路就是 在导出的时候,利用DataTable做中间变量 ...

  2. 二次封装dojo slider

    上次的二次封装timeslider,挺有意思,又来封装一个dojo的,样式还是用arcgis的.实现更多功能,包括HorizontalSlider和VerticalSlider, 刻度的显示隐藏,标签 ...

  3. VMware中对Linux虚拟机的网络配置静态IP的配置

    前言 踏出象牙塔,进入公司,由于公司的所有产品都是Linux下的,必然自己这段时间需要在自己的工作机器先学习一下.项目代码是用Source Insight进行查看的,总是Ctrl + Alt的切来切去 ...

  4. WPF自定义控件(三)

    今天我们开始制作我们的按钮,主要的效果就是一个按钮正常状态.鼠标滑过.按下三态显示不同的图片. 首先我们需要给扩展按钮添加三个属性,分别是正常状态图片,鼠标滑过图片,按钮按下图片. 先贴出Button ...

  5. tfsenflow队列|tf.train.slice_input_producer|tf.train.Coordinator|tf.train.start_queue_runners

      #### ''' tf.train.slice_input_producer :定义样本放入文件名队列的方式[迭代次数,是否乱序],但此时文件名队列还没有真正写入数据 slice_input_pr ...

  6. java中封装的使用方法(工具myeclipse)

    封装可以实现属性私有化,将类的属性修饰符由public改为private,如此做者,其他类就无法访问该类中被private修饰的对象,一般我们会使用setter/getter()方法实现对这些对象的访 ...

  7. 转载:LESS基本用法

    转载出处:https://blog.csdn.net/qq_38209578/article/details/80566860 转载出处:https://blog.csdn.net/weixin_44 ...

  8. Hadoop2.2.0在Ubuntu编译失败解决方法

    [INFO] ------------------------------------------------------------------------ [INFO] BUILD FAILURE ...

  9. ret/retn人为改变执行地址

    1.CALL和RET/RETN是一对指令,CALL把返回地址压入堆栈,RET/RETN把返回地址从堆栈取出,然后将IP寄存器改为该返回地址.  2.不使用CALL,而是人为地把地址放入堆栈即可实现.如 ...

  10. python-opencv实现简单的车牌定位

    车牌定位的原理:https://blog.csdn.net/relocy/article/details/78705662 训练好的分类器:https://github.com/zeusees/Hyp ...