zz:https://blog.csdn.net/rzo_kqp_orz/article/details/52280525
小Z又开始了ETG。ETG的地图是树形的,相邻两个房间有一定距离,一开始,系统会随机断掉一条边,这样,这张
地图就被分成了两个连通块。显然,狡猾的系统会把四个宝箱两两分布在每个联通的最远点对上。一开始,小Z会
出生在一个有宝箱的房间(系统还是有点良心的),然后小Z“咚咚咚咚”一路过关斩将走到有另外一个宝箱的所
在地(显然小Z走最短路),到达第二个宝箱所在地后,系统会又很良心地把他送到另一个连通块的某个宝箱处,
然后小Z又“咚咚咚咚咚”,拿到了最后一个宝箱。然后,他就通关了。显然对小Z来说通关是肯定的,所以小Z想
知道他最多会走多少距离。
Input
输入第一行包含一个整数N,表示房间个数。
接下来N-1行,每行3个正整数x,y,d表示,房间x与房间y的距离为d。
N<=100,000 ,di<=100,000 。
Output
输出一行,包含一个整数,表示小Z最远走的距离。
Sample Input
6
1 3 4
2 3 1
2 5 3
2 6 2
3 4 5
Sample Output
14
Data Constraint
对于50%的数据满足N<=1000 。
对于100%的数据满足
一句话题意
给出一棵树,你可以选择断掉某一条边,然后取生成的两棵树的直径和。求这个和的最大值。
【50%】n<=1000
枚举断哪一条边,然后暴力求直径。
【100%解法1】n<=10^5
用线段树维护树的直径。
枚举断哪一条边,这相当于分离出原树的一棵子树,我们可以在线段树中查找到这棵子树的直径,然后剩下的区间合并一下得到另一个直径。
如果用倍增求lca时间是O(n log^2),会被卡。
如果用rmq求lca时间是O(n log)
//线段树维护树的直径:http://blog.csdn.net/rzo_kqp_orz/article/details/52280811
【100%解法2】
题解说这是裸的树形dp!?
题解原话:“裸的树形 DP,记录 d1[i] (最长链),d2[i] (次长链),fa[i] ( i 的父亲及以上的最长路)即可。时间复杂度O(n)。”
思路是非常简单的,但是维护过程打起来讨论较多。
#include<cmath> #include<cstdio> #include<algorithm> #define fo(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--) using namespace std; typedef long long LL; const int maxn=(1e5)+5, MX=18; struct TR{ int x,y; LL len; TR(int X=0,int Y=0,LL LEN=0) {x=X, y=Y, len=LEN;} }; int n; int tot,go[2*maxn],next[2*maxn],f1[maxn]; LL val[2*maxn]; void ins(int x,int y,LL z) { go[++tot]=y; val[tot]=z; next[tot]=f1[x]; f1[x]=tot; } int fa[2*maxn][MX+5],deep[maxn],ap[2*maxn],fir[2*maxn],Log[2*maxn],er[MX+5]; void rmq_pre() { fo(i,1,ap[0]) fa[i][0]=ap[i], Log[i]=log(i)/log(2); fo(i,0,MX) er[i]=1<<i; fo(j,1,MX) fo(i,1,ap[0]) { fa[i][j]=fa[i][j-1]; if (i+er[j-1]<=ap[0] && deep[fa[i+er[j-1]][j-1]]<deep[fa[i][j]]) fa[i][j]=fa[i+er[j-1]][j-1]; } } int lca(int x,int y) { x=fir[x], y=fir[y]; if (x>y) swap(x,y); int t=Log[y-x+1]; return (deep[fa[x][t]]<deep[fa[y-er[t]+1][t]]) ?fa[x][t] :fa[y-er[t]+1][t] ; } int st[maxn],en[maxn],sum,Tbh[maxn]; LL dis[maxn]; void dfs_pre(int k,int last,LL s) { deep[k]=deep[last]+1; dis[k]=s; ap[++ap[0]]=k, fir[k]=ap[0]; Tbh[++sum]=k, st[k]=sum; for(int p=f1[k]; p; p=next[p]) if (go[p]!=last) { dfs_pre(go[p],k,s+val[p]); ap[++ap[0]]=k; } en[k]=sum; } TR tr[4*maxn]; LL DIS(int x,int y) {return dis[x]+dis[y]-dis[lca(x,y)]*2;} TR merge(TR a,TR b) { TR re= (a.len>b.len) ?a :b; if (DIS(a.x,b.x)>re.len) re=TR(a.x,b.x,DIS(a.x,b.x)); if (DIS(a.x,b.y)>re.len) re=TR(a.x,b.y,DIS(a.x,b.y)); if (DIS(a.y,b.x)>re.len) re=TR(a.y,b.x,DIS(a.y,b.x)); if (DIS(a.y,b.y)>re.len) re=TR(a.y,b.y,DIS(a.y,b.y)); return re; } void tr_js(int k,int l,int r) { if (l==r) { tr[k].x=tr[k].y=Tbh[l]; tr[k].len=0; return; } int t=k<<1, t1=(l+r)>>1; tr_js(t,l,t1), tr_js(t+1,t1+1,r); tr[k]=merge(tr[t],tr[t+1]); } TR tr_cx(int k,int l,int r,int x,int y) { if (l==x && r==y) return tr[k]; int t=k<<1, t1=(l+r)>>1; if (y<=t1) return tr_cx(t,l,t1,x,y); else if (x>t1) return tr_cx(t+1,t1+1,r,x,y); else return merge(tr_cx(t,l,t1,x,t1),tr_cx(t+1,t1+1,r,t1+1,y)); } LL ans; void dfs(int k,int last) { for(int p=f1[k]; p; p=next[p]) if (go[p]!=last) { int St=st[go[p]], En=en[go[p]]; if (St==1) { ans=max(ans,tr_cx(1,1,n,St,En).len+tr_cx(1,1,n,En+1,n).len); } else if (En==n) { ans=max(ans,tr_cx(1,1,n,1,St-1).len+tr_cx(1,1,n,St,En).len); } else { TR t=merge(tr_cx(1,1,n,1,St-1),tr_cx(1,1,n,En+1,n)); ans=max(ans,t.len+tr_cx(1,1,n,St,En).len); } dfs(go[p],k); } } int main() { scanf("%d",&n); fo(i,1,n-1) { int x,y; LL d; scanf("%d %d %lld",&x,&y,&d); ins(x,y,d), ins(y,x,d); } dfs_pre(1,0,0); rmq_pre(); tr_js(1,1,n); dfs(1,0); printf("%lld\n",ans); } #include <cstdio> #include <cstring> #include <algorithm> #define i64 long long using namespace std; const int N = 1e5 + 10; int n, r[N], tot; i64 ans; struct edge{int t, l, n;} e[N * 2]; struct link { i64 v1, v2, v3; int u1, u2, u3; void ins(int u, i64 v) { if (v > v1) u3 = u2, v3 = v2, u2 = u1, v2 = v1, u1 = u, v1 = v; else if (v > v2) u3 = u2, v3 = v2, u2 = u, v2 = v; else if (v > v3) u3 = u, v3 = v; } } l[N]; i64 max(i64 x, i64 y) {return x > y ? x : y;} void add(int x, int y, int z) { e[++ tot].t = y; e[tot].l = z; e[tot].n = r[x]; r[x] = tot; } void dfs(int u, int fa) { l[u].u1 = l[u].u2 = l[u].v1 = l[u].v2 = 0; for (int i = r[u]; i; i = e[i].n) { int v = e[i].t; if (v == fa) continue; dfs(v, u); i64 t = l[v].v1 + e[i].l; l[u].ins(v, t); } } void awn(int u, int fa, i64 ll, i64 mx) { for (int i = r[u]; i; i = e[i].n) { int v = e[i].t; if (v == fa) continue; i64 t = 0, mm = 0; if (l[u].u1 == v) t = l[u].v2; else t = l[u].v1; if (l[u].u1 == v) mm = l[u].v2 + l[u].v3; else if (l[u].u2 == v) mm = l[u].v1 + l[u].v3; else mm = l[u].v1 + l[u].v2; ans = max(ans, l[v].v1 + l[v].v2 + max(mm, max(mx, ll + t))); awn(v, u, max(ll, t) + e[i].l, max(mm, max(mx, ll + t))); } } int main() { scanf("%d", &n); 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); } dfs(1, 0); awn(1, 0, 0, 0); printf("%lld", ans); return 0; }