题意:
一颗树,定义一条路径的权值等于路径的边权之和,需要求这颗树所有路径中权值的最大值

思路:

考虑到路径权值与点权的最值有关,而最值的问题通常可以通过排序就行处理,于是想到先把点权排序。

容易看出如果某条路径的权值是通过某个点算出的最小 ,那么肯定这条路径肯定不会经过权值更小的点,于是有了两种处理思路

1.按点权从小到大删点,对于即将删除的点,比他权值小的点已经被删去了,所以只要在当前状态的森林里找一条最长路径乘以次点权就可以更新答案

2.按点权从大到小加点,显然新加进来的点权值最小,当前树里的任何路径的点权最小值都不会小于新加进来的点,所以可以通过维护直径来更新答案

对于思路1,如果是一条链的话,对于一个将要删除的点,可以直接二分得到当前点附近已经被删除的点并更新答案,然而在树里面就不太好从处理了,至少我肯定是不会的

于是考虑思路2:

加点建树很明显可以通过并查集维护

但是在树的合并过程中怎么维护直径呢?这里需要用到一个定理。。一颗树的直径的两个端点一定是他子树直径的端点

于是就可以进行直径的维护了,具体求距离可以选择logn的lca

代码:

 #include <bits/stdc++.h>
using namespace std;
long long f[];
// 节点编号[1,n]
// 最大节点数
#define MAXN 200010
// 满足2^M > MAXN
#define M 20
struct node
{
long long to,val;
};
struct tree
{
long long r,x,y;
void clear()
{
r=;
x=y=-;
}
}t[];
vector<node>g[];
long long d[];
long long n;
int a[];
long long ans;
long long ch[MAXN]={}; // 节点i下面的孩子的个数(包括i)
long long fa[MAXN][M+]; // ch[i][j]表示与节点i距离为2^j的i的祖先
long long len[MAXN][M+];
long long deep[MAXN]={}; // i的深度(根节点的深度为1)
// 初始化deep数组,ch数组,fa数组的初始值
// 默认根节点为1
long long dfs(int cur=, int father = ,long long val=)
{
deep[cur] = deep[father]+;
fa[cur][] = father;
len[cur][]=val;
ch[cur] = ;
int sz = g[cur].size();
for(int i=;i<sz;i++)
{
if(g[cur][i].to != father)
ch[cur] += dfs(g[cur][i].to,cur,g[cur][i].val);
}
return ch[cur];
}
// 初始化fa数组
void initFa(int n)
{
for(int i=;i<=;i++)
for(int node=;node<=n;node++)
{
fa[node][i] = fa[fa[node][i-]][i-];
len[node][i]= len[fa[node][i-]][i-]+len[node][i-];
}
}
// 将node上升height的高度
int binaryRaise(int node, int height,long long &val)
{
val=;
for(int i=M; i>=; i--)
{
if(fa[node][i] && height >= (<<i))
{
val+=len[node][i];
node = fa[node][i];
height -= (<<i);
}
}
return node;
}
// a的深度比b大
long long lca(int a, int b)
{
if(a==||b==)
return -;
// 先移动a到与b同样深度的地方
if(deep[a]<deep[b])
swap(a,b);
long long res=;
a = binaryRaise(a, deep[a]-deep[b],res);
if(a==b) // 此时,b就是a和b的公共祖先
//return a;
return res;
for(int i=M;i>=;i--)
{
if(a!=b && fa[a][i]!=fa[b][i])
{
res+=len[a][i];
a = fa[a][i];
res+=len[b][i];
b = fa[b][i];
}
} return res+len[a][]+len[b][];
}
int find(int a)
{
if(f[a]==a||f[a]==-)
return f[a]=a;
f[a]=find(f[f[a]]);
t[a]=t[f[a]];
return f[a];
}
int uni(int a,int b)
{
int x=find(a),y=find(b);
return f[y]=x;
}
bool issame(int a,int b)
{
return find(a)==find(b);
} bool cmp(int a,int b)
{
return d[a]>d[b];
}
void merg(int a,int b)
{
int fb=find(b);
long long l11=lca(t[a].x,t[fb].x);
long long l12=lca(t[a].x,t[fb].y);
long long l21=lca(t[a].y,t[fb].x);
long long l22=lca(t[a].y,t[fb].y);
long long maxl=max(max(max(max(max(l11,l12),l21),l22),t[a].r),t[fb].r);
int x1=t[a].x;
int x2=t[fb].x;
int y1=t[a].y;
int y2=t[fb].y;
if(l11==maxl)
{
t[a].x=x1;
t[a].y=x2;
}
if(l12==maxl)
{
t[a].x=x1;
t[a].y=y2;
}
if(l21==maxl)
{
t[a].x=y1;
t[a].y=x2;
}
if(l22==maxl)
{
t[a].x=y1;
t[a].y=y2;
}
if(t[a].r==maxl)
{
t[a].x=x1;
t[a].y=y1;
}
if(t[fb].r==maxl)
{
t[a].x=x2;
t[a].y=y2;
}
t[a].r=maxl;
f[fb]=a;
}
void put(int p)
{
t[p]=tree{,p,p};
f[p]=p;
for(int i=;i<(int)g[p].size();i++)
{
int to=g[p][i].to;
if(f[to]==-)
continue;
merg(p,to);
}
ans=max(ans,d[p]*t[p].r);
}
int main()
{
freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
memset(ch,,sizeof(ch));
memset(fa,,sizeof(fa));
memset(len,,sizeof(len));
memset(deep,,sizeof(deep));
//scanf("%I64d",&n);
scanf("%lld",&n);
for(int i=;i<=n;i++)
g[i].clear();
for(int i=;i<=n;i++)
{
scanf("%lld",d+i);
a[i-]=i;
}
int x,y;
long long v;
for(int i=;i<n;i++)
{
//scanf("%d%d%I64d",&x,&y,&v);
scanf("%d%d%lld",&x,&y,&v);
g[x].push_back(node{y,v});
g[y].push_back(node{x,v});
}
dfs();
initFa(n);
sort(a,a+n,cmp);
memset(f,-,sizeof(f));
memset(t,,sizeof(t));
ans=-;
for(int i=;i<n;i++)
{
put(a[i]);
}
//printf("%I64d\n",ans);
printf("%lld\n",ans);
}
return ;
}

思路2:对点考虑, 对于当前点s(每次选取重心), 可以求出以它为根, 每一个子树上的点上到s的点权最小值, 和边权和, 然后 把每一个每一个子树分类, 这是为了避免计算的结果在同一个子树里。

然后计算不同子树中的结果, 这里计算结果时需要排个序, 按照点权最小值从大到小排序, 每次选取两个属于不同子树的最大边权和。

如此递归计算即可

 #include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+;
int siz[MAXN], n, val[MAXN];
bool center[MAXN]; typedef pair<int, int>pii;
struct Edge{
int to, next;
int c;
}e[MAXN * ];
int head[MAXN], edge_tot;
void Add_Edge(int x, int y, int z){
e[edge_tot].to = y;
e[edge_tot].next = head[x];
e[edge_tot].c = z;
head[x] = edge_tot++;
} void init (){
edge_tot = ;
memset(head, -, sizeof (head));
memset(center, , sizeof (center));
} pair <pair<long long, long long>, int>Mval[MAXN];
pii Find(int s, int pa, int tot) {
pii res = make_pair(INT_MAX, -);
int m = ;
siz[s] = ;
for (int i = head[s]; ~i; i = e[i].next) {
int u = e[i].to;
if (u == pa || center[u]) {
continue;
}
res = min(res, Find(u, s, tot));
siz[s] += siz[u];
m = max(m, siz[u]);
}
m = max(m, tot-siz[s]);
return min(res, make_pair(m, s));
} int idx, tim;
void Get_Min_Sum(int u, int pa, long long minval, long long sum){
Mval[idx++] = make_pair(make_pair(minval, sum), tim);
for (int i = head[u]; ~i; i = e[i].next){
int v = e[i].to;
if (v != pa && !center[v]){
Get_Min_Sum(v, u, min(minval, (long long)val[v]), sum+e[i].c);
}
}
}
long long sub_solve(){
sort (Mval, Mval+idx);
long long res = ;
long long sum1 = Mval[idx-].first.second, sum2 = ;
int t1 = Mval[idx-].second;
for (int i = idx-; i >= ; i--){
if (Mval[i].second != t1){
res = max(res, Mval[i].first.first*(Mval[i].first.second+sum1));
}else{
res = max(res, Mval[i].first.first*(Mval[i].first.second+sum2));
}
long long tmp = Mval[i].first.second;
if (tmp > sum1){
if (Mval[i].second == t1){
sum1 = tmp;
}else{
sum2 = sum1;
//t2 = t1;
sum1 = tmp;
t1 = Mval[i].second;
} }else{
if (tmp > sum2 && Mval[i].second != t1){
sum2 = tmp;
//t2 = Mval[i].second;
}
} }
return res;
}
long long solve (int u, int tot){
int g = Find(u, , tot).second;
center[g] = true;
long long res = ;
idx = ;
//tim++;
Mval[idx++] = make_pair(make_pair(val[g],), tim);
for (int i = head[g]; ~i; i = e[i].next){
int v = e[i].to;
int cost = e[i].c;
if (!center[v]){
tim++;
Get_Min_Sum(v, g, min(val[v], val[g]), cost);
}
}
res = max(res, sub_solve());
for (int i = head[g]; ~i; i = e[i].next){
int v = e[i].to;
if (!center[v]){
res = max(res, solve(v, siz[v]));
}
}
return res;
} int main()
{
//freopen("in.txt", "r", stdin);
int T;
scanf ("%d", &T);
while (T--){
init();
tim = ;
scanf ("%d", &n);
for (int i = ; i < n; i++){
scanf ("%d", val+i+);
}
for (int i = ; i < n-; i++){
int u, v, c;
scanf ("%d%d%d", &u, &v, &c);
Add_Edge(u, v, c);
Add_Edge(v, u, c);
}
long long res = solve(, n);
printf("%lld\n", res); }
return ;
}

计蒜客 444 / xtuoj 1024 京东的物流路径(并查集+离线lca)或者 (点分治)的更多相关文章

  1. 2018 计蒜之道复赛 贝壳找房魔法师顾问(并查集+dfs判环)

    贝壳找房在遥远的传奇境外,找到了一个强大的魔法师顾问.他有 22 串数量相同的法力水晶,每个法力水晶可能有不同的颜色.为了方便起见,可以将每串法力水晶视为一个长度不大于 10^5105,字符集不大于  ...

  2. 2019icpc徐州站 Cat 计蒜客 - 42540 && The Answer to the Ultimate Question of Life, The Universe, and Everything. 计蒜客 - 42545

    VJ链接:https://vjudge.net/contest/412095#problem/A Cat 计蒜客 - 42540 题意: 给你一个区间[L,R],给你现在拥有的钱S.你需要从[L,R] ...

  3. 计蒜客 作弊揭发者(string的应用)

    鉴于我市拥堵的交通状况,市政交管部门经过听证决定在道路两侧安置自动停车收费系统.当车辆驶入车位,系统会通过配有的摄像头拍摄车辆画面,通过识别车牌上的数字.字母序列识别车牌,通过连接车管所车辆信息数据库 ...

  4. 计蒜客的一道题dfs

    这是我无聊时在计蒜客发现的一道题. 题意: 蒜头君有一天闲来无事和小萌一起玩游戏,游戏的内容是这样的:他们不知道从哪里找到了N根不同长度的木棍, 看谁能猜出这些木棍一共能拼出多少个不同的不等边三角形. ...

  5. 计蒜客模拟赛5 D2T1 成绩统计

    又到了一年一度的新生入学季了,清华和北大的计算机系同学都参加了同一场开学考试(因为两校兄弟情谊深厚嘛,来一场联考还是很正常的). 不幸的是,正当老师要统计大家的成绩时,世界上的所有计算机全部瘫痪了. ...

  6. 计蒜客 等边三角形 dfs

    题目: https://www.jisuanke.com/course/2291/182238 思路: 1.dfs(int a,int b,int c,int index)//a,b,c三条边的边长, ...

  7. 计蒜客 方程的解数 dfs

    题目: https://www.jisuanke.com/course/2291/182237 思路: 来自:https://blog.csdn.net/qq_29980371/article/det ...

  8. 计蒜客 买书 dfs

    题目: https://www.jisuanke.com/course/2291/182236 思路: 递归解决,从第一本书开始,每本书都有两种选择: //index是book里面每本书价格的下标, ...

  9. 计蒜客:Entertainment Box

    Ada, Bertrand and Charles often argue over which TV shows to watch, and to avoid some of their fight ...

随机推荐

  1. Java虚拟机内存区域堆(heap)的管理

    在上一节中Java 出现内存溢出的定位以及解决方案 中对于Java虚拟机栈以及方法区的内存出现的异常以及处理方式进行了解析,由于Java虚拟机对于堆的管理十分复杂,并且Java虚拟机中最基本的内存区域 ...

  2. Android 仿Win8的metro的UI界面(上)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/23441455 昨晚没事手机下载了一些APP,发现现在仿win8的主界面越来越多, ...

  3. Android组件间的数据传输

    组件我们有了,那么我们缺少一个组件之间传递信息的渠道.利用Intent做载体,这是一个王道的做法.还有呢,可以利用文件系统来做数据共享.也可以使用Application设置全局数据,利用组件来进行控制 ...

  4. ANDROID内存优化(大汇总——上)

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上 ...

  5. 快速优化yum (for centos5.5)

    定义yum超时时间:vi /etc/yum.conftimeout=120 修改源:(全部复制粘贴即可)cd /etc/yum.repos.d/mv rhel-debuginfo.repo rhel- ...

  6. Verilog中锁存器与多路选择器

    Verilog中锁存器与多路选择器 Verilog是一种硬件描述语言,它代表的是硬件. Verilog代表的就是逻辑门和连接线. 对于一个always@(*)控制的块而言,只要块中的表达式包含的任意的 ...

  7. JNI Java调用C代码 示例

    Activity public class MainActivity extends ListActivity {     static {         System.loadLibrary(&q ...

  8. 原生js-拉勾网首页效果

    拉勾网首页公司广告位的悬浮划过效果着实很吸引我.如下(不会做动图!--,感兴趣的可以去拉勾看看): 此处最吸引我的地方在于将鼠标划过上面一排公司列表时,感觉像是绿色的区块跟着你的鼠标移动一样,颇有动感 ...

  9. Shell中逻辑判断

    [ 条件1 -a 条件2 ]   当1和2都真时才为真 [ 条件1 -o 条件2 ]   当1和2其中一个为真即为真 [ ! 条件 ]           取反   &&     与 ...

  10. Cacti添加IO模板并监控磁盘IO

    1.下载Cacti_Net-SNMP_DevIO_v3.1.zip 下载Cacti_Net-SNMP_DevIO_v3.1.zip,解压并上传net-snmp_devio.xml到/resource/ ...