[CSP-S模拟测试]:影子(并查集+LCA)
题目描述
一个人有很多的影子,新的旧的,他们不断消失重来。学者的影子在他苍白色的精神图景里成为了$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$分。
代码时刻
#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to,w;}e[200001];
int head[100001],cnt;
int n;
int f[100001],lft[100001],rht[100001],rk[100001];
int fa[100001][21],depth[100001];
long long dis[100001],len[100001];
pair<int,int> d[100001];
long long ans;
void pre_work()
{
memset(len,0,sizeof(len));
memset(head,0,sizeof(head));
memset(depth,0,sizeof(depth));
ans=cnt=0;
for(int i=1;i<=n;i++)f[i]=lft[i]=rht[i]=i;
}
void add(int x,int y,int w)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
e[cnt].w=w;
head[x]=cnt;
}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void dfs(int x)
{
for(int i=head[x];i;i=e[i].nxt)
{
if(depth[e[i].to])continue;
depth[e[i].to]=depth[x]+1;
fa[e[i].to][0]=x;
for(int j=1;j<=20;j++)
fa[e[i].to][j]=fa[fa[e[i].to][j-1]][j-1];
dis[e[i].to]=dis[x]+e[i].w;
dfs(e[i].to);
}
}
int LCA(int x,int y)
{
int minn=1<<30;
if(depth[x]>depth[y])swap(x,y);
for(int i=20;~i;i--)
if(depth[fa[y][i]]>=depth[x])
y=fa[y][i];
if(x==y)return x;
for(int i=20;~i;i--)
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
return fa[x][0];
}
long long get_dis(int x,int y){return dis[x]+dis[y]-(dis[LCA(x,y)]<<1);}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
pre_work();
for(int i=1;i<=n;i++)
{
int x;scanf("%d",&x);
d[i]=make_pair(x,i);
}
sort(d+1,d+n+1,greater<pair<int,int> >());
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
depth[1]=1;
dfs(1);
for(int i=1;i<=n;i++)rk[d[i].second]=i;
for(int i=1;i<=n;i++)
{
for(int j=head[d[i].second];j;j=e[j].nxt)
{
int to=find(e[j].to);
if(rk[d[i].second]<rk[to])continue;
len[0]=len[d[i].second],lft[0]=lft[d[i].second],rht[0]=rht[d[i].second];
if(len[to]>len[0]){len[0]=len[to];lft[0]=lft[to];rht[0]=rht[to];}
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];}
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];}
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];}
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];}
f[to]=d[i].second;lft[d[i].second]=lft[0];rht[d[i].second]=rht[0];len[d[i].second]=len[0];
}
ans=max(ans,len[d[i].second]*d[i].first);
}
printf("%lld\n",ans);
}
return 0;
}
rp++
[CSP-S模拟测试]:影子(并查集+LCA)的更多相关文章
- hdu 2874 Connections between cities (并查集+LCA)
Connections between cities Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (J ...
- hdu6074[并查集+LCA+思维] 2017多校4
看了标答感觉思路清晰了许多,用并查集来维护全联通块的点数和边权和. 用另一个up[]数组(也是并查集)来保证每条边不会被重复附权值,这样我们只要将询问按权值从小到大排序,一定能的到最小的边权和与联通块 ...
- [CSP-S模拟测试]:Dash Speed(线段树+并查集+LCA)
题目描述 比特山是比特镇的飙车圣地.在比特山上一共有$n$个广场,编号依次为$1$到$n$,这些广场之间通过$n−1$条双向车道直接或间接地连接在一起,形成了一棵树的结构. 因为每条车道的修建时间以及 ...
- Gym 100814C Connecting Graph 并查集+LCA
Description standard input/output Statements Alex is known to be very clever, but Walter does not be ...
- Network-POJ3694并查集+LCA
Network Time Limit: 5000MS Memory Limit: 65536K Description A network administrator manages ...
- [并查集+LCA USACO18OPEN ] Disruption
https://www.luogu.org/problemnew/show/P4374 一看这道题就是一个妙题,然后题解什么树链剖分...珂朵莉树... 还不如并查集来的实在!我们知道并查集本来就是路 ...
- Mobile Phone Network CodeForces - 1023F(并查集lca+修改环)
题意: 就是有几个点,你掌控了几条路,你的商业对手也掌控了几条路,然后你想让游客都把你的所有路都走完,那么你就有钱了,但你又想挣的钱最多,真是的过分..哈哈 游客肯定要对比一下你的对手的路 看看那个便 ...
- HDU6074 Phone Call (并查集 LCA)
Phone Call Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Tota ...
- 习题:过路费(kruskal+并查集+LCA)
过路费 [问题描述]在某个遥远的国家里,有 n 个城市.编号为 1,2,3,…,n.这个国家的政府修 建了 m 条双向道路,每条道路连接着两个城市.政府规定从城市 S 到城市 T 需 要收取的过路费 ...
随机推荐
- 10.15 sed 命令实践
在n行前插入 [root@wen data]# sed '2i 106,dandan,CSO' person.txt101,oldboy,CEO106,dandan,CSO102,zhangyao,C ...
- Borůvka (Sollin) 算法求 MST 最小生成树
基本思路: 用定点数组记录每个子树的最近邻居. 对于每一条边进行处理: 如果这条边连成的两个顶点同属于一个集合,则不处理,否则检测这条边连接的两个子树,如果是连接这两个子树的最小边,则更新 (合并). ...
- 数据挖掘之DecisionTreeClassifier决策树
用决策树DecisionTreeClassifier的数据挖掘算法来通过三个参数,Pclass,Sex,Age,三个参数来求取乘客的获救率. 分为三大步: 一,创建决策树DecisionTreeCla ...
- 头疼3-4次的问题,数据从DB导出到EXCEL,再从EXCEL导入到DB,数据格式发生错误 ,导致 程序出错。
反思: 1 解决 问题的思路 绕远了: 在这个问题出现前,程序是运行正确 的 问题出现前,我误删了DB 的 testcase表的所有 case ,然后 再把邮件 中的excel数据导入到 DB 然后 ...
- Python笔记(四)_字符串的方法
字符串的方法 []表示该参数时可选的,start和end参数表示范围 count(sub[, start[, end]]) 返回sub在字符串里边出现的次数 find(sub[, start[, en ...
- Android深度探索-卷1第四章心得体会
这一章的和三章的git用法有联系,so,吧上一章的git基本用法搞好了再来,具体的方法就是看书上网查,这里就不做详细步骤介绍了.这章就有点意思了,是源码的下载和编译,有能看的,能自己鼓捣的,本章介绍的 ...
- ThinkPHP内置标签库原理(Cx标签库)
任何一个模板引擎的功能都不可能是为你量身定制的,具有一个良好的可扩展 机制也是模板引擎的另外一个考量,Smarty采用的是插件方法来实现扩展,ThinkTemplate由于采用了标签库技术,比Smar ...
- python-javascript之dom
DOM DOM:(document object mode)文档对象模型.DOM为文档提供了结构化表示,并定义了如何通过脚本来访问文档结构. 目的就是为了能让js操作html元素而制定的一个规范 DO ...
- 用其他音乐源帮帮网易云,Ubuntu听歌利器
镜像文章 1.用其他音乐源帮帮网易云,Android听歌利器 2.用其他音乐源帮帮网易云,Windows听歌利器 众所周知,国内只有网易云推出了Linux的客户端,在Listen 1并不十分好用的基础 ...
- ubuntu 配置php环境
第一步:先更新 sudo apt-get update 第二步:安装 安装 Apache2: sudo apt-get install apache2 安装PHP模块: sudo apt-get in ...