Jzoj4727 挺进
题意:给你一颗树,要求断掉一条边,使得剩下两个联通快的直径之和最大
一看就是树形DP嘛,c1表示最长边c2次长,f表示父亲部分的最长路
上面做法不讲,我们讲一种比较新奇的方法
假设我们枚举断哪一条边,在lgn时间内求出两个联通快的直径不就行了嘛
怎么做呢,我们发现,可以用树的dfs序来维护,我们用一个线段树维护一个区间内的直径的端点和长度
额,如何合并?
我们假设两块的直径端点分别为x1,y1,x2,y2,那么结果就是在这四个点中取2个的所有方案的最大值(证明显然)
但是这道题这样做复杂度较高(n lg^2 n),如果求lca能用rmq就可以将为(n lg n),然而我比较懒用了树剖,而且jz跑的快就过了
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100010
#define LL long long
using namespace std;
struct Edge{ int v,c,nt; } G[N<<1];
struct Node{ int x,y; LL v; } s[N<<2];
int h[N],sz[N],son[N],top[N],d[N],f[N];
int n,cnt=0,clk=0,nl[N],nr[N],c[N]; LL dis[N];
inline void adj(int x,int y,int c){
G[++cnt]=(Edge){y,c,h[x]}; h[x]=cnt;
}
void dfs(int x,int p){
d[x]=d[p]+1; f[x]=p; sz[x]=1;
for(int v,i=h[x];i;i=G[i].nt)
if((v=G[i].v)!=p){
dis[v]=dis[x]+G[i].c;
dfs(v,x); sz[x]+=sz[v];
if(sz[v]>sz[son[x]]) son[x]=v;
}
}
void dgs(int x,int p){
nl[x]=++clk; c[clk]=x; top[x]=p;
if(son[x]) dgs(son[x],p);
for(int v,i=h[x];i;i=G[i].nt)
if((v=G[i].v)!=f[x] && v!=son[x]) dgs(v,v);
nr[x]=clk;
}
inline LL gLca(int x,int y){
if(!x || !y) return 0;
LL S=dis[x]+dis[y];
for(;top[x]!=top[y];y=f[top[y]])
if(d[top[x]]>d[top[y]]) swap(x,y);
return S-((d[x]<d[y]?dis[x]:dis[y])<<1);
}
inline Node gNod(int x,int y){ return (Node){x,y,gLca(x,y)}; }
inline Node max(Node a,Node b){ return a.v<b.v?b:a; }
inline Node merge(Node a,Node b){
return max(max(a,b),max(max(gNod(a.x,b.x),gNod(a.x,b.y)),max(gNod(a.y,b.x),gNod(a.y,b.y))));
}
void build(int l,int r,int x){
if(l==r){ s[x]=(Node){c[l],c[l],0}; return; }
int m=l+r>>1;
build(l,m,x<<1);
build(m+1,r,x<<1|1);
s[x]=merge(s[x<<1],s[x<<1|1]);
}
Node query(int l,int r,int x,int L,int R){
if(L>R) return (Node){0,0,0};
if(L<=l && r<=R) return s[x];
int m=l+r>>1; Node A=(Node){0,0,-1};
if(L<=m) A=query(l,m,x<<1,L,R);
if(m<R) A=merge(A,query(m+1,r,x<<1|1,L,R));
return A;
}
int main(){
scanf("%d",&n);
for(int x,y,c,i=1;i<n;++i){
scanf("%d%d%d",&x,&y,&c);
adj(x,y,c); adj(y,x,c);
}
dfs(1,0); dgs(1,1); build(1,n,1);
LL A=0;
for(int i=2;i<=n;++i){
Node a,b,c;
a=query(1,n,1,nl[i],nr[i]);
b=query(1,n,1,1,nl[i]-1);
c=query(1,n,1,nr[i]+1,n);
A=max(A,a.v+merge(b,c).v);
}
printf("%lld\n",A);
}