cunzai_zsy0531

关注我

P4220 [WC2018]通道 题解

题面

跟暴力写挂有点像,但是这次是三棵树的距离之和最大。考虑在第一棵树上点分治,合并两个儿子子树,求其中的最大值。这个过程可以合并果子,花费 \(1\log\)。在合并的时候拿出这些点来在第二棵树上建虚树,在虚树上 dp,每个位置维护子树内分别在要合并的两个子树(设为 \(0,1\))的直径(包括第三棵树)。这样在每个位置统计以这个位置作为第二棵树上 \(lca\) 的路径最大值。复杂度 \(O(n\log^2 n)\)

点击查看代码
inline void clearvector(std::vector<int> &a){std::vector<int> b;std::swap(a,b);}
const int N=1e5+13;
struct Edge{int v;ll w;int nxt;};
int n;ll ans;
namespace tree2{ll dis[N];bool vis[N];inline void build(std::vector<int> a);}
namespace tree3{
inline ll calc(int u,int v);
struct Node{
	int x,y;ll d;
	inline bool operator <(const Node &a)const{return d>a.d;}
	inline Node operator +(const Node &a)const{
		static Node b[6];b[0]=(Node){x,y,d},b[1]=(Node){a.x,a.y,a.d};
		b[2]=(Node){x,a.x,calc(x,a.x)},b[3]=(Node){x,a.y,calc(x,a.y)};
		b[4]=(Node){y,a.x,calc(y,a.x)},b[5]=(Node){y,a.y,calc(y,a.y)};
		int o=0;for(int i=1;i<6;++i)if(b[i]<b[o]) o=i;
		return b[o];
	}
}f[N][2];
inline void update(int u,int v);
}

namespace tree1{
Edge e[N<<1];
int h[N],etot;
inline void add_edge(int u,int v,ll w){e[++etot]=(Edge){v,w,h[u]};h[u]=etot;}
inline void readedge(){for(int i=1;i<n;++i){int u,v;ll w;read(u),read(v),read(w);add_edge(u,v,w),add_edge(v,u,w);}}
int siz[N],maxx[N],rt,psum;
bool vis[N];
std::vector<int> g[N];
ll dis[N];
void findrt(int u,int f){
	siz[u]=1,maxx[u]=0;
	for(int i=h[u];i;i=e[i].nxt){
		int v=e[i].v;if(v==f||vis[v]) continue;
		findrt(v,u);
		siz[u]+=siz[v];
		maxx[u]=max(maxx[u],siz[v]);
	}
	maxx[u]=max(maxx[u],psum-siz[u]);
	if(maxx[u]<maxx[rt]) rt=u;
}
void dfs(int u,int f,ll dist,int topf){
	dis[u]=dist;g[topf].pb(u);
	for(int i=h[u];i;i=e[i].nxt){
		int v=e[i].v;if(v==f||vis[v]) continue;
		dfs(v,u,dist+e[i].w,topf);
	}
}
void solve(int u){
	vis[u]=1;dis[u]=0;clearvector(g[u]),g[u].pb(u);
	std::set<pii> t;t.insert(mp(g[u].size(),u));
	for(int i=h[u];i;i=e[i].nxt){
		int v=e[i].v;if(vis[v]) continue;
		clearvector(g[v]);
		dfs(v,u,e[i].w,v);
		t.insert(mp(g[v].size(),v));
	}
	while(t.size()>1){
		std::set<pii>::iterator it=t.begin();int x=it->se;t.erase(it);
		it=t.begin();int y=it->se;t.erase(it);
		for(auto v:g[x]) tree2::vis[v]=1,tree3::f[v][0]=(tree3::Node){v,v,tree2::dis[v]<<1},tree3::f[v][1]=(tree3::Node){0,0,0};
		for(auto v:g[y]) tree2::vis[v]=1,tree3::f[v][1]=(tree3::Node){v,v,tree2::dis[v]<<1},tree3::f[v][0]=(tree3::Node){0,0,0};
		for(auto v:g[x]) g[y].pb(v);
		t.insert(mp(g[y].size(),y));
		tree2::build(g[y]);
		for(auto v:g[y]) tree2::vis[v]=0;
	}
	for(int i=h[u];i;i=e[i].nxt){
		int v=e[i].v;if(vis[v]) continue;
		rt=0,psum=siz[v];
		findrt(v,0),findrt(rt,0);
		solve(rt);
	}
}
inline void work(){
	maxx[rt=0]=INF,psum=n;
	findrt(1,0);findrt(rt,0);
	solve(rt);
}
}

namespace tree2{
struct Stack{
	int s[N],t;
	inline void clear(){s[t=0]=0;}
	Stack(){clear();}
	inline void push(int x){s[++t]=x;}
	inline void pop(){--t;}
	inline int ttop(){return s[t-1];}
	inline int top(){return s[t];}
	inline bool empty(){return !t;}
};
Edge e[N<<1];
int h[N],etot;
inline void add_edge(int u,int v,ll w){e[++etot]=(Edge){v,w,h[u]};h[u]=etot;}
inline void readedge(){for(int i=1;i<n;++i){int u,v;ll w;read(u),read(v),read(w);add_edge(u,v,w),add_edge(v,u,w);}}
int fa[N],siz[N],dep[N],son[N],top[N],id[N],dfs_clock;
void dfs1(int u,int f,int deep){
	fa[u]=f,siz[u]=1,dep[u]=deep;
	for(int i=h[u];i;i=e[i].nxt){
		int v=e[i].v;if(v==f) continue;
		dis[v]=dis[u]+e[i].w;
		dfs1(v,u,deep+1);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]]) son[u]=v;
	}
}
void dfs2(int u,int topf){
	top[u]=topf,id[u]=++dfs_clock;
	if(!son[u]) return;
	dfs2(son[u],topf);
	for(int i=h[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(v!=son[u]&&v!=fa[u]) dfs2(v,v);
	}
}
inline int lca(int u,int v){
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		u=fa[top[u]];
	}
	return dep[u]<dep[v]?u:v;
}
inline void init(){dfs1(1,0,0);dfs2(1,1);}
inline ll dist(int u,int v){return dis[u]+dis[v]-2*dis[lca(u,v)];}
inline bool cmp(const int &x,const int &y){return id[x]<id[y];}
inline void build(std::vector<int> a){
	Stack st;
	std::sort(a.begin(),a.end(),cmp);
	st.push(1);if(!vis[1]) tree3::f[1][0]=tree3::f[1][1]=(tree3::Node){0,0,0};
	for(int i=0,lim=a.size();i<lim;++i){
		if(a[i]==1) continue;
		int t=lca(a[i],st.top());
		if(t!=st.top()){
			while(st.t>1&&id[t]<id[st.ttop()]) tree3::update(st.ttop(),st.top()),st.pop();
			if(t!=st.ttop()){
				if(!vis[t]) tree3::f[t][0]=tree3::f[t][1]=(tree3::Node){0,0,0};
				tree3::update(t,st.top()),st.pop(),st.push(t);
			}
			else tree3::update(t,st.top()),st.pop();
		}
		st.push(a[i]);
	}
	for(int i=st.t-1;i;--i) tree3::update(st.s[i],st.s[i+1]);
}
}

namespace tree3{
Edge e[N<<1];
int h[N],etot;
inline void add_edge(int u,int v,ll w){e[++etot]=(Edge){v,w,h[u]};h[u]=etot;}
inline void readedge(){for(int i=1;i<n;++i){int u,v;ll w;read(u),read(v),read(w);add_edge(u,v,w),add_edge(v,u,w);}}
int fa[N],siz[N],dep[N],son[N],top[N];
ll dis[N];
void dfs1(int u,int f,int deep){
	fa[u]=f,siz[u]=1,dep[u]=deep;
	for(int i=h[u];i;i=e[i].nxt){
		int v=e[i].v;if(v==f) continue;
		dis[v]=dis[u]+e[i].w;
		dfs1(v,u,deep+1);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]]) son[u]=v;
	}
}
void dfs2(int u,int topf){
	top[u]=topf;
	if(!son[u]) return;
	dfs2(son[u],topf);
	for(int i=h[u];i;i=e[i].nxt){
		int v=e[i].v;
		if(v!=son[u]&&v!=fa[u]) dfs2(v,v);
	}
}
inline int lca(int u,int v){
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		u=fa[top[u]];
	}
	return dep[u]<dep[v]?u:v;
}
inline void init(){dfs1(1,0,0);dfs2(1,1);}
inline ll dist(int u,int v){return dis[u]+dis[v]-2*dis[lca(u,v)];}
inline ll calc(int u,int v){if(!u||!v) return 0;return tree1::dis[u]+tree1::dis[v]+tree2::dis[u]+tree2::dis[v]+dist(u,v);}
inline void update(int u,int v){
	ans=max(ans,calc(f[u][0].x,f[v][1].x)-(tree2::dis[u]<<1));ans=max(ans,calc(f[u][0].x,f[v][1].y)-(tree2::dis[u]<<1));
	ans=max(ans,calc(f[u][0].y,f[v][1].x)-(tree2::dis[u]<<1));ans=max(ans,calc(f[u][0].y,f[v][1].y)-(tree2::dis[u]<<1));
	ans=max(ans,calc(f[u][1].x,f[v][0].x)-(tree2::dis[u]<<1));ans=max(ans,calc(f[u][1].x,f[v][0].y)-(tree2::dis[u]<<1));
	ans=max(ans,calc(f[u][1].y,f[v][0].x)-(tree2::dis[u]<<1));ans=max(ans,calc(f[u][1].y,f[v][0].y)-(tree2::dis[u]<<1));
	f[u][0]=f[u][0]+f[v][0],f[u][1]=f[u][1]+f[v][1];
}
}

int main(){
#ifdef LOCAL
	freopen("0.3.in","r",stdin);
//	freopen("tunnel.out","w",stdout);
#endif
	read(n);
	tree1::readedge();
	tree2::readedge();tree2::init();
	tree3::readedge();tree3::init();
	tree1::work();
	println(ans);
	return 0;
}
posted @ 2022-05-13 23:01  cunzai_zsy0531  阅读(26)  评论(0编辑  收藏  举报