挺进

挺进

题意:给你一颗树,要求断掉一条边,使得剩下两个联通快的直径之和最大

假设我们枚举断哪一条边,在logn时间内求出两个联通快的直径(树剖lca) 不就行了嘛

怎么做呢,我们发现,可以用树的dfs序来维护,我们用一个线段树维护一个区间内的直径的端点和长度

如何合并呢?

我们假设两块的直径端点分别为x1,y1,x2,y2,那么结果就是在这四个点中取2个的所有方案的最大值

具体细节见代码

#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
#define int long long
#define ls (p<<1)
#define rs (p<<1|1)
#define mid ((l+r)>>1)
// typedef long long int;
const int N=200010;
inline int read() {
	int x=0;char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
	return x;
}

int n;
int hd[N],tot,to[N],nxt[N],w[N];
inline void add(int x,int y,int z) {
	to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
}

int dis[N];
int fa[N],dep[N],siz[N],son[N];
void dfs_son(int x,int f) {
	fa[x]=f;siz[x]=1;dep[x]=dep[f]+1;
	for(int i=hd[x];i;i=nxt[i]) {
		int y=to[i];
		if(y==f) continue;
		dis[y]=dis[x]+w[i];
		dfs_son(y,x);
		siz[x]+=siz[y];
		if(siz[y]>siz[son[x]]) son[x]=y;
	}
}

int dfnin[N],dfnout[N],rev[N],top[N],dfn_cnt;
void dfs_chain(int x,int tp) {
	top[x]=tp;
	dfnin[x]=++dfn_cnt;rev[dfn_cnt]=x;
	if(son[x]) dfs_chain(son[x],tp);
	for(int i=hd[x];i;i=nxt[i]) {
		int y=to[i];
		if(dfnin[y]) continue;
		dfs_chain(y,y);
	}	
	dfnout[x]=dfn_cnt;
}

inline int get_dia(int x,int y) {
	if(!x||!y) return 0;
	int sum=dis[x]+dis[y];
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	return sum-(dep[x]<dep[y]?dis[x]:dis[y])*2;
}

struct TREE{
	int x,y;
	int v;
	TREE() {}
	TREE(int x_,int y_,int v_) {x=x_;y=y_;v=v_;}
}t[N<<1];
TREE Max(TREE a,TREE b) {return a.v<b.v?b:a;}
TREE get(int a,int b) {return TREE(a,b,get_dia(a,b));}
TREE merge(TREE a,TREE b) {
	return Max(Max(a,b),Max(Max(get(a.x,b.x),get(a.y,b.y)),Max(get(a.x,b.y),get(a.y,b.x))));
}
void build(int l,int r,int p) {
	if(l==r) {
		t[p]=TREE(rev[l],rev[l],0);
		return;
	}
	build(l,mid,ls);
	build(mid+1,r,rs);
	t[p]=merge(t[ls],t[rs]);
}
TREE query(int l,int r,int L,int R,int p) {
	if(L>R) return TREE(0,0,0);
	if(L<=l&&r<=R) return t[p];
	TREE res=TREE(0,0,-1);
	if(L<=mid) res=query(l,mid,L,R,ls);
	if(R>mid) res=merge(res,query(mid+1,r,L,R,rs));
	return res;
}
signed main() {
	n=read();
	for(int i=1,x,y,z;i<n;i++) {
		x=read();y=read();z=read();
		add(x,y,z);
		add(y,x,z);
	}
	dfs_son(1,0);
	dfs_chain(1,1);
	build(1,n,1);
	int ans=0;
	for(int i=1;i<n;i++) {
		TREE a=query(1,n,dfnin[i],dfnout[i],1);
		TREE b=query(1,n,1,dfnin[i]-1,1);
		TREE c=query(1,n,dfnout[i]+1,n,1);
		ans=max(ans,a.v+merge(b,c).v);
	}
	printf("%lld
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/ke-xin/p/13526065.html