Jzoj4727 挺进

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

一看就是树形DP嘛,c1表示最长边c2次长,f表示父亲部分的最长路

上面做法不讲,我们讲一种比较新奇的方法

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

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

额,如何合并?

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

但是这道题这样做复杂度较高(n lg^2 n),如果求lca能用rmq就可以将为(n lg n),然而我比较懒用了树剖,而且jz跑的快就过了

#include
#include
#include
#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]1);
}
inline Node gNod(int x,int y){ return (Node){x,y,gLca(x,y)}; }
inline Node max(Node a,Node b){ return a.vinline 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(m1,r,x<<1|1,L,R));
	return A;
}
int main(){
	scanf("%d",&n);
	for(int x,y,c,i=1;iscanf("%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);
}

你可能感兴趣的:(OI,数据结构,----线段树,求解策略,----动态规划,Jzoj)