【BZOJ2870】—最长道路Tree(边分治)

传送门


边分治比点分治好的一点就是每次分出来都只有2个集合
如果遇到难以合并的信息的时候边分治就很有用了

手动转二叉树

每次可以按照权值大小排序后对两个集合双指针扫两遍
具体实现可以看代码

复杂度O(nlog2n)O(nlog^2n)

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
const int N=200005;
const int inf=1e9;
int n,pn,mx,mxsiz,tot,rt;
ll ans;
int adj[N],nxt[N<<1],to[N<<1],siz[N],val[N<<1],vis[N<<1],cnt=1,pt[2],a[N];
pii tmp[2][N];
#define fi first
#define se second
inline bool comp(const pii &a,const pii &b){
	return a.fi>b.fi;
}
vector<int> son[N];
inline void addedge(int u,int v,int w){
	nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
}
void dfs(int u,int f){
	for(int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(v==f)continue;
		son[u].pb(v),dfs(v,u);
	}
}
inline void rebuild(){
	cnt=1;memset(adj,0,sizeof(adj));
	for(int u=1;u<=n;u++){
		if(son[u].size()<=2){
			for(int i=0,len=son[u].size();i<len;i++){
				int v=son[u][i];
				addedge(u,v,v<=pn),addedge(v,u,v<=pn);
			}
		}
		else{
			int f1=++n,f2=++n;a[f1]=a[f2]=a[u];
			addedge(u,f1,0),addedge(f1,u,0),addedge(f2,u,0),addedge(u,f2,0);
			for(int i=0,len=son[u].size();i<len;i++){
				if(i&1)son[f2].pb(son[u][i]);
				else son[f1].pb(son[u][i]);
			}
		}
	}
}
inline void getrt(int u,int f){
	siz[u]=1;
	for(int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(vis[e>>1]||v==f)continue;
		getrt(v,u),siz[u]+=siz[v];
		int k=max(siz[v],mxsiz-siz[v]);
		if(k<mx)mx=k,rt=e;
	}
}
void getdis(int kd,int u,int f,int dep,int va){
	va=min(va,a[u]),tmp[kd][++pt[kd]]=pii(va,dep);
	for(int e=adj[u];e;e=nxt[e]){
		int v=to[e];
		if(vis[e>>1]||v==f)continue;
		getdis(kd,v,u,dep+val[e],va);
	}
}
void solve(int u,int sz){
	mxsiz=sz,mx=inf;
	getrt(u,0);
	if(mx==inf)return;
	int now=rt;vis[now>>1]=1;
	pt[0]=pt[1]=0,getdis(0,to[now],0,0,inf),getdis(1,to[now^1],0,0,inf);
	sort(tmp[0]+1,tmp[0]+pt[0]+1,comp),sort(tmp[1]+1,tmp[1]+pt[1]+1,comp);
	for(int i=1,j=1,mxl=0;i<=pt[0];i++){
		while(j<=pt[1]&&tmp[1][j].fi>=tmp[0][i].fi)mxl=max(mxl,tmp[1][j].se),j++;
		if(j!=1)ans=max(ans,1ll*tmp[0][i].fi*(mxl+tmp[0][i].se+val[now]+1));
	}
	for(int i=1,j=1,mxl=0;i<=pt[1];i++){
		while(j<=pt[0]&&tmp[0][j].fi>=tmp[1][i].fi)mxl=max(mxl,tmp[0][j].se),j++;
		if(j!=1)ans=max(ans,1ll*tmp[1][i].fi*(mxl+tmp[1][i].se+val[now]+1));
	}
	int ksz=siz[to[now]];solve(to[now],ksz),solve(to[now^1],sz-ksz);
}
int main(){
	n=pn=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		addedge(u,v,1),addedge(v,u,1);
	}
	dfs(1,0),rebuild(),solve(1,n);
	cout<<ans;
}
posted @ 2019-05-03 16:32  Stargazer_cykoi  阅读(233)  评论(0编辑  收藏  举报