锟题x1

以下用$d_k(x,y)$表示$x,y$在第树$k$上的距离,$h_k(x)$表示$x$在树$k$上的深度

先做两棵树,即最大化$d_1(x,y)+d_2(x,y)=h_1(x)+h_1(y)-2h_1(lca)+d_2(x,y)$,其中$lca$是$x,y$在树$1$上的lca

考虑在树$1$上枚举$lca$,即是要最大化$h_1(x)+h_2(y)+d_2(x,y)$,于是我们可以对每个树$2$的点$i$建多一条边$(i,i',h_1(i))$,在dfs树$1$的同时维护(树$1$的子树中的每个$x$对应到树$2$的$x'$这些点在树$2$中的直径)即可

现在有了树$3$,考虑对其边分治,设分治到$(u,v)$,我们要查询在树$3$上跨过$(u,v)$的答案,这其实就是在两棵树的基础上加了$d_3(x,u)+d_3(y,v)+w_{u,v}$还有路径$(x,y)$必须经过$(u,v)$的约束,那么将当前分治范围内的点拿出来在树$1$上建虚树,并给$(u,v)$两边的点染不同的颜色,于是接下来我们维护不同颜色的直径,之后就和两棵树完全一样了

最后的一个小问题就是边分治的复杂度,这里直接多叉转二叉即可(对每个点新建一条$0$链)

说起来很简单,但写起来还是挺长的

#include<stdio.h>
#include<algorithm>
#include<vector>
#include<assert.h>
using namespace std;
typedef long long ll;
const int inf=2147483647;
int n;
struct tree1{
	int h[100010],nex[200010],to[200010],M;
	ll v[200010];
	void add(int a,int b,ll c){
		M++;
		to[M]=b;
		v[M]=c;
		nex[M]=h[a];
		h[a]=M;
	}
	int fa[100010],dfn[100010],mn[200010][18],dep[200010],lg[200010];
	ll d[100010];
	void dfs(int x){
		dfn[x]=++M;
		mn[M][0]=x;
		dep[x]=dep[fa[x]]+1;
		for(int i=h[x];i;i=nex[i]){
			if(to[i]!=fa[x]){
				fa[to[i]]=x;
				d[to[i]]=d[x]+v[i];
				dfs(to[i]);
				mn[++M][0]=x;
			}
		}
	}
	int qmin(int x,int y){return dep[x]<dep[y]?x:y;}
	int query(int l,int r){
		int k=lg[r-l+1];
		return qmin(mn[l][k],mn[r-(1<<k)+1][k]);
	}
	int lca(int x,int y){
		if(dfn[x]>dfn[y])swap(x,y);
		return query(dfn[x],dfn[y]);
	}
	void gao(){
		int i,j,x,y;
		ll z;
		for(i=1;i<n;i++){
			scanf("%d%d%lld",&x,&y,&z);
			add(x,y,z);
			add(y,x,z);
		}
		M=0;
		dfs(1);
		for(j=1;j<18;j++){
			for(i=1;i+(1<<j)-1<=M;i++)mn[i][j]=qmin(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
		}
		for(i=2;i<=M;i++)lg[i]=lg[i>>1]+1;
	}
}t1;
struct tree2{
	int h[100010],nex[200010],to[200010],M;
	ll v[200010];
	void add(int a,int b,ll c){
		M++;
		to[M]=b;
		v[M]=c;
		nex[M]=h[a];
		h[a]=M;
	}
	int fa[100010],lg[200010],in[100010];
	ll d[100010],mn[200010][19];
	void dfs(int x){
		in[x]=++M;
		mn[M][0]=d[x];
		for(int i=h[x];i;i=nex[i]){
			if(to[i]!=fa[x]){
				fa[to[i]]=x;
				d[to[i]]=d[x]+v[i];
				dfs(to[i]);
				mn[++M][0]=d[x];
			}
		}
	}
	ll query(int l,int r){
		int k=lg[r-l+1];
		return min(mn[l][k],mn[r-(1<<k)+1][k]);
	}
	ll dis(int x,int y){
		if(in[x]>in[y])swap(x,y);
		return d[x]+d[y]-2*query(in[x],in[y]);
	}
	void gao(){
		int i,j,x,y;
		ll z;
		for(i=1;i<n;i++){
			scanf("%d%d%lld",&x,&y,&z);
			add(x,y,z);
			add(y,x,z);
		}
		M=0;
		dfs(1);
		for(j=1;j<19;j++){
			for(i=1;i+(1<<j)-1<=M;i++)mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
		}
		for(i=2;i<=M;i++)lg[i]=lg[i>>1]+1;
	}
}t2;
struct pr{
	int to;
	ll v;
	pr(int a=0,ll b=0){to=a;v=b;}
};
struct tree3{
	int h[200010],nex[400010],to[400010],M;
	ll v[400010];
	void ins(int a,int b,ll c){
		M++;
		to[M]=b;
		v[M]=c;
		nex[M]=h[a];
		h[a]=M;
	}
	void add(int a,int b,ll c){
		ins(a,b,c);
		ins(b,a,c);
	}
	vector<pr>g[100010];
	int N;
	void dfs(int fa,int x){
		int p;
		vector<pr>::iterator it;
		if(g[x].size()){
			p=0;
			for(it=g[x].begin();it!=g[x].end();it++){
				if(it->to!=fa){
					if(p){
						N++;
						add(p,N,0);
						add(N,it->to,it->v);
						p=N;
					}else{
						add(x,it->to,it->v);
						p=x;
					}
				}
			}
		}
		for(it=g[x].begin();it!=g[x].end();it++){
			if(it->to!=fa)dfs(x,it->to);
		}
	}
	void gao(){
		int i,x,y;
		ll z;
		for(i=1;i<n;i++){
			scanf("%d%d%lld",&x,&y,&z);
			g[x].push_back(pr(y,z));
			g[y].push_back(pr(x,z));
		}
		N=n;
		M=1;
		dfs(0,1);
	}
}t3;
ll dis[200010],ad;
ll get(int x,int y){
	return t2.dis(x,y)+t1.d[x]+t1.d[y]+dis[x]+dis[y]+ad;
}
struct dia{
	int x,y;
	dia(int a=0,int b=0){x=a;y=b;}
};
ll max(dia a,dia b){
	if(a.x==0||b.x==0)return 0;
	return max(max(get(a.x,b.x),get(a.x,b.y)),max(get(a.y,b.x),get(a.y,b.y)));
}
dia operator+(dia a,dia b){
	if(a.x==0)return b;
	if(b.x==0)return a;
	int x,y;
	ll mx=0,t;
	#define ch(u,v) t=get(u,v);\
					if(t>mx){\
						x=u;\
						y=v;\
						mx=t;\
					}
	ch(a.x,a.y)
	ch(b.x,b.y)
	ch(a.x,b.x)
	ch(a.x,b.y)
	ch(a.y,b.x)
	ch(a.y,b.y)
	return dia(x,y);
}
struct pd{
	dia x,y;
	pd(dia a=0,dia b=0){x=a;y=b;}
	dia&operator[](int k){return k?x:y;}
};
pd operator+(pd a,pd b){return pd(a.x+b.x,a.y+b.y);}
ll max(pd a,pd b){return max(max(a.x,b.y),max(a.y,b.x));}
ll ans;
bool vis[400010];
int siz[200010],p[200010],M;
void dfs1(int fa,int x){
	if(x<=n)p[++M]=x;
	siz[x]=1;
	for(int i=t3.h[x];i;i=t3.nex[i]){
		if(!vis[i]&&t3.to[i]!=fa){
			dfs1(x,t3.to[i]);
			siz[x]+=siz[t3.to[i]];
		}
	}
}
int al,mn,cn;
void dfs2(int fa,int x){
	for(int i=t3.h[x];i;i=t3.nex[i]){
		if(!vis[i]&&t3.to[i]!=fa){
			dfs2(x,t3.to[i]);
			if(abs(al-2*siz[t3.to[i]])<mn){
				mn=abs(al-2*siz[t3.to[i]]);
				cn=i;
			}
		}
	}
}
struct vtree{
	int h[100010],nex[100010],to[100010],M;
	void add(int a,int b){
		M++;
		to[M]=b;
		nex[M]=h[a];
		h[a]=M;
	}
	int col[100010];
	pd dfs(int x){
		pd d,t;
		d[col[x]]=dia(x,x);
		for(int i=h[x];i;i=nex[i]){
			t=dfs(to[i]);
			ans=max(ans,max(d,t)-2*t1.d[x]);
			d=d+t;
		}
		h[x]=0;
		return d;
	}
}vt;
bool cmp(int x,int y){return t1.dfn[x]<t1.dfn[y];}
int st[100010],tp;
void insert(int x){
	if(!tp){
		st[++tp]=x;
		return;
	}
	int l=t1.lca(x,st[tp]);
	while(tp>1&&t1.dep[st[tp-1]]>t1.dep[l]){
		vt.add(st[tp-1],st[tp]);
		tp--;
	}
	if(t1.dep[st[tp]]>t1.dep[l]){
		vt.add(l,st[tp]);
		tp--;
	}
	if(t1.dep[st[tp]]<t1.dep[l])st[++tp]=l;
	st[++tp]=x;
}
void build(){
	int i;
	sort(p+1,p+M+1,cmp);
	tp=0;
	for(i=1;i<=M;i++)insert(p[i]);
	for(i=1;i<tp;i++)vt.add(st[i],st[i+1]);
	if(st[1]!=1)vt.add(1,st[1]);
}
void dfs3(int fa,int x,int f){
	if(x<=n)vt.col[x]=f;
	for(int i=t3.h[x];i;i=t3.nex[i]){
		if(!vis[i]&&t3.to[i]!=fa){
			dis[t3.to[i]]=dis[x]+t3.v[i];
			dfs3(x,t3.to[i],f);
		}
	}
}
void solve(int x){
	int y;
	M=0;
	dfs1(0,x);
	al=siz[x];
	mn=inf;
	cn=0;
	dfs2(0,x);
	if(cn==0)return;
	vis[cn]=vis[cn^1]=1;
	x=t3.to[cn];
	y=t3.to[cn^1];
	build();
	dis[x]=dis[y]=0;
	dfs3(0,x,0);
	dfs3(0,y,1);
	ad=t3.v[cn];
	vt.dfs(1);
	vt.M=0;
	solve(x);
	solve(y);
}
int main(){
	scanf("%d",&n);
	t1.gao();
	t2.gao();
	t3.gao();
	solve(1);
	printf("%lld",ans);
}

[UOJ347]通道的更多相关文章

  1. 【UOJ347】【WC2018】通道 边分治 虚树 DP

    题目大意 给你三棵树,点数都是\(n\).求 \[ \max_{i,j}d_1(i,j)+d_2(i,j)+d_3(i,j) \] 其中\(d_k(i,j)\)是在第\(k\)棵数中\(i,j\)两点 ...

  2. UOJ347 WC2018 通道 边分治、虚树

    传送门 毒瘤数据结构题qwq 设三棵树分别为$T1,T2,T3$ 先将$T1$边分治,具体步骤如下: ①多叉树->二叉树,具体操作是对于每一个父亲,建立与儿子个数相同的虚点,将父亲与这些虚点穿成 ...

  3. Paypal开发中遇到请求被中止: 未能创建 SSL/TLS 安全通道及解决方案

    最近在基于ASP.NET上开发了Paypal支付平台,在ASP.NET开发的过程中没有遇到这个问题,但是引用到MVC开发模式中的时候就出现了"未能创建 SSL/TLS 安全通道及解决方案&q ...

  4. JAVA NIO Socket通道

      DatagramChannel和SocketChannel都实现定义读写功能,ServerSocketChannel不实现,只负责监听传入的连接,并建立新的SocketChannel,本身不传输数 ...

  5. 学习 opencv---(4) 分离颜色通道 && 多通道混合

    上篇文章中我们讲到了使用addWeighted函数进行图像混合操作,以及将ROI和addWeighted函数结合起来使用,对指定区域进行图像混合操作. 而为了更好地观察一些图像材料的特征,有时需要对R ...

  6. 关于QImage提取单色通道方法(vector)

    转载请标明处: 作者:微微苏荷 本文地址:关于QImage提取单色通道方法(vector) 近日,用QT和mxnet结合做一个图像识别的demo.遇到需要把图片从QImage转为vector单色分离的 ...

  7. 基于暗通道优先算法的去雾应用(Matlab/C++)

    基于暗通道优先的单幅图像去雾算法(Matlab/C++) 算法原理:             参见论文:Single Image Haze Removal Using Dark Channel Pri ...

  8. Java NIO4:Socket通道

    Socket通道 上文讲述了通道.文件通道,这篇文章来讲述一下Socket通道,Socket通道与文件通道有着不一样的特征,分三点说: 1.NIO的Socket通道类可以运行于非阻塞模式并且是可选择的 ...

  9. Java NIO3:通道和文件通道

    通道是什么 通道式(Channel)是java.nio的第二个主要创新.通道既不是一个扩展也不是一项增强,而是全新的.极好的Java I/O示例,提供与I/O服务的直接连接.Channel用于在字节缓 ...

随机推荐

  1. SVG(可缩放矢量图形)

        SVG可缩放矢量图形(Scalable Vector Graphics)是基于可扩展标记语言(XML),用于描述二维矢量图形的一种图形格式.SVG是W3C("World Wide W ...

  2. Centos 7 安装jdk1.7

    在linux中安装jdk是很平凡的事情了,刚学习linux给自己留下一笔记.刚安装centos其中可以会附带jdk,但是这并不影响,只要下载自己的jdk然后替换相对应的环境变量即可. 1.下载相对应的 ...

  3. <script>标签的属性

    1.async 表示立即下载资源,但不妨碍下载其他资源或等待加载其他脚本,脚本相对于页面的其它部分异步执行,只对外部脚本文件有效 2.defer 表示脚本可以延迟到文档完全被解析和显示之后再执行,只对 ...

  4. 第一章: 文件句柄转化为 typeglob/glob 与文件句柄检测

    #为了使在子例程中传递文件句柄不出问题 #我们要把文件句柄转为glob或typeglob #转为glob $fd = *MY_FILE; #转为typeblog $fd = \*MY_FILE; #两 ...

  5. document.onclick在ios上不触发的解决方法与touchstart点击穿透处理

    document.onclick = function (e) { var e = e ? e : window.event; var tar = e.srcElement || e.target; ...

  6. Vue-$emit的用法

    1.父组件可以使用 props 把数据传给子组件.2.子组件可以使用 $emit 触发父组件的自定义事件. vm.$emit( event, arg ) //触发当前实例上的事件 vm.$on( ev ...

  7. python实战===一键刷屏

    #当按键q的时候,自动输入 “大家好!”并回车键发送!from pynput import keyboard from pynput.keyboard import Key, Controller k ...

  8. 006 Java并发编程wait、notify、notifyAll和Condition

    原文https://www.cnblogs.com/dolphin0520/p/3920385.html#4182690 Java并发编程:线程间协作的两种方式:wait.notify.notifyA ...

  9. HTML5 一篇就够的中文教程

    HTML5 是近十年来 Web 开发标准最巨大的飞跃.HTML5 并非仅仅用来表示 Web 内容,它将 Web 带入一个成熟的应用平台,在 HTML5 平台上,视频.音频.图象.动画,以及同电脑的交互 ...

  10. JavaScript知识点的总结

    一.Javascript的含义 是一种解释性的语言,主要给网页添加各色各样的动态功能,同时为用户提供浏览效果. 二.JavaScript的主要特点 1. 简单性 2. 动态性 3. 安全性 4. 跨平 ...