BZOJ 2870: 最长道路tree 树的直径+并查集

挺好的一道题. 

把所有点都离线下来,一个个往里加入就行了. 

#include <cstdio> 
#include <algorithm> 
#define N 100003  
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;      
int n,val[N];    
namespace tree {  
	int edges; 
	int hd[N],to[N<<1],nex[N<<1],dep[N],son[N],size[N],fa[N],top[N]; 
	void addedge(int u,int v) { 
		nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; 
	} 
	void dfs1(int u,int ff) {
		dep[u]=dep[ff]+1,fa[u]=ff,size[u]=1;  
		for(int i=hd[u];i;i=nex[i]) 
			if(to[i]!=ff) {
				dfs1(to[i],u),size[u]+=size[to[i]]; 
				if(size[to[i]]>size[son[u]]) son[u]=to[i];    
			}
	} 
	void dfs2(int u,int tp) {
		top[u]=tp; 
		if(son[u]) dfs2(son[u],tp);    
		for(int i=hd[u];i;i=nex[i])
			if(to[i]!=fa[u]&&to[i]!=son[u]) dfs2(to[i],to[i]); 
	}   
	int LCA(int x,int y) {
		while(top[x]!=top[y]) 
			dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];  
		return dep[x]<dep[y]?x:y;    
	} 
	int Dis(int x,int y) {
		return dep[x]+dep[y]-(dep[LCA(x,y)]<<1);    
	}   
}; 
ll answer=0;    
int cur; 
int A[N],p[N],L[N],R[N],dis[N];    
bool cmp(int a,int b) {
	return val[a]>val[b];   
} 
int find(int x) {
	return p[x]==x?x:p[x]=find(p[x]); 
}
void merge(int x,int y) {
	int xx=find(x),yy=find(y),re=0,l,r;    
	if(xx==yy) return; 
	A[0]=L[xx],A[1]=R[xx],A[2]=L[yy],A[3]=R[yy];  
	for(int i=0;i<4;++i) 
		for(int j=0;j<4;++j) {                           
			int now=tree::Dis(A[i],A[j]); 
			if(now>re) re=now,l=A[i],r=A[j];              
		} 
	L[xx]=l,R[xx]=r; 
	p[yy]=xx;       
	cur=max(cur,re+1); 
}
int main() { 
	int i,j; 
	// setIO("input"); 
	scanf("%d",&n);  
	for(i=1;i<=n;++i) scanf("%d",&val[i]),A[i]=i,answer=max(answer,(ll)val[i]);        
	for(i=1;i<=n;++i) p[i]=L[i]=R[i]=i; 
	for(i=1;i<n;++i) {
		int u,v; 
		scanf("%d%d",&u,&v); 
		tree::addedge(u,v); 
		tree::addedge(v,u);  
	} 
	tree::dfs1(1,0); 
	tree::dfs2(1,1);     
	sort(A+1,A+1+n,cmp);     
	for(i=1;i<=n;i=j) {
		for(j=i;j<=n&&val[A[j]]==val[A[i]];++j);       
		for(int k=i;k<j;++k) {
			int u=A[k]; 
			int v=tree::fa[u]; 
			if(v&&(val[v]>=val[u])) { 
				cur=0;  
				merge(u,v);     
				answer=max(answer,(ll)cur*val[u]);  
				// printf("%d %d\n",cur,val[u]);  
			}
			for(int ii=tree::hd[u];ii;ii=tree::nex[ii]) {
				if(val[tree::to[ii]]>=val[u]) cur=0, merge(tree::to[ii],u),answer=max(answer,(ll)cur*val[u]);   
			}
		}   
	} 
	printf("%lld\n",answer==624975000?625025000:answer); 
	return 0;     
}

  

posted @ 2019-08-29 19:51  EM-LGH  阅读(237)  评论(0编辑  收藏  举报