计蒜客 444 / xtuoj 1024 京东的物流路径(并查集+离线lca)或者 (点分治)
2015-07-28 11:25
316 查看
题意:
一颗树,定义一条路径的权值等于路径的边权之和,需要求这颗树所有路径中权值的最大值
思路:
考虑到路径权值与点权的最值有关,而最值的问题通常可以通过排序就行处理,于是想到先把点权排序。
容易看出如果某条路径的权值是通过某个点算出的最小 ,那么肯定这条路径肯定不会经过权值更小的点,于是有了两种处理思路
1.按点权从小到大删点,对于即将删除的点,比他权值小的点已经被删去了,所以只要在当前状态的森林里找一条最长路径乘以次点权就可以更新答案
2.按点权从大到小加点,显然新加进来的点权值最小,当前树里的任何路径的点权最小值都不会小于新加进来的点,所以可以通过维护直径来更新答案
对于思路1,如果是一条链的话,对于一个将要删除的点,可以直接二分得到当前点附近已经被删除的点并更新答案,然而在树里面就不太好从处理了,至少我肯定是不会的
于是考虑思路2:
加点建树很明显可以通过并查集维护
但是在树的合并过程中怎么维护直径呢?这里需要用到一个定理。。一颗树的直径的两个端点一定是他子树直径的端点
于是就可以进行直径的维护了,具体求距离可以选择logn的lca
代码:
View Code
一颗树,定义一条路径的权值等于路径的边权之和,需要求这颗树所有路径中权值的最大值
思路:
考虑到路径权值与点权的最值有关,而最值的问题通常可以通过排序就行处理,于是想到先把点权排序。
容易看出如果某条路径的权值是通过某个点算出的最小 ,那么肯定这条路径肯定不会经过权值更小的点,于是有了两种处理思路
1.按点权从小到大删点,对于即将删除的点,比他权值小的点已经被删去了,所以只要在当前状态的森林里找一条最长路径乘以次点权就可以更新答案
2.按点权从大到小加点,显然新加进来的点权值最小,当前树里的任何路径的点权最小值都不会小于新加进来的点,所以可以通过维护直径来更新答案
对于思路1,如果是一条链的话,对于一个将要删除的点,可以直接二分得到当前点附近已经被删除的点并更新答案,然而在树里面就不太好从处理了,至少我肯定是不会的
于是考虑思路2:
加点建树很明显可以通过并查集维护
但是在树的合并过程中怎么维护直径呢?这里需要用到一个定理。。一颗树的直径的两个端点一定是他子树直径的端点
于是就可以进行直径的维护了,具体求距离可以选择logn的lca
代码:
#include <bits/stdc++.h> using namespace std; const int MAXN = 1e5+10; int siz[MAXN], n, val[MAXN]; bool center[MAXN]; typedef pair<int, int>pii; struct Edge{ int to, next; int c; }e[MAXN * 2]; 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 = 0; memset(head, -1, sizeof (head)); memset(center, 0, 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, -1); int m = 0; siz[s] = 1; 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 = 0; long long sum1 = Mval[idx-1].first.second, sum2 = 0; int t1 = Mval[idx-1].second; for (int i = idx-2; i >= 0; 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, 0, tot).second; center[g] = true; long long res = 0; idx = 0; //tim++; Mval[idx++] = make_pair(make_pair(val[g],0), 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 = 0; scanf ("%d", &n); for (int i = 0; i < n; i++){ scanf ("%d", val+i+1); } for (int i = 0; i < n-1; 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(1, n); printf("%lld\n", res); } return 0; }
View Code
相关文章推荐
- Spring工作原理
- 重置root密码
- 7月英语学习总结
- ios背景更新和下载
- 人工神经网络基础与研究内容
- DriveInfo类查看磁盘信息
- 兔子产子问题
- 暑假- Trie树-(G - IMMEDIATE DECODABILITY)
- 电商的秒杀和抢购
- Linux下Nagios的安装与配置详解
- 从BSP模型到Apache Hama
- C语言中结构体的位域
- onclientclick和onclick区别
- [技巧心得] 高效整洁CSS代码原则
- ERROR: operator does not exist: character = integer
- Visual Studio 2012 keyboard shortcuts
- hadoop2.6完全分布式安装HBase1.1
- flask0.1源码阅读
- transform(变形)和transform-origin(变形原点)
- 基于PHP文件操作实现页面统计