锟题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. bzoj 2434 fail tree+dfs序

    首先比较明显的是我们可以将字符串组建立ac自动机,那么对于询问s1字符串在s2字符串中出现的次数,就是在以s1结尾为根的fail tree中,子树有多少个节点是s2的节点,这样我们处理fail tre ...

  2. 2018DDCTF Misc部分WP

    题目给出了这样一串字符:d4e8e1f4a0f7e1f3a0e6e1f3f4a1a0d4e8e5a0e6ece1e7a0e9f3baa0c4c4c3d4c6fbb9e1e6b3e3b9e4b3b7b7 ...

  3. linux平台学x86汇编语言学习集合帖

    linux平台学x86汇编语言学习集合帖 linux平台学x86汇编(一):https://blog.csdn.net/shallnet/article/details/45543237 linux平 ...

  4. 多线程伪共享FalseSharing

    1. 伪共享产生: 在SMP架构的系统中,每个CPU核心都有自己的cache,当多个线程在不同的核心上,并且某线程修改了在同一个cache line中的数据时,由于cache一致性原则,其他核心cac ...

  5. linux arm的存储分布那些事之一

    转自:http://blog.csdn.net/xiaojsj111/article/details/11724081   linux arm 内存分布总览   上图是linux的arm的虚拟地址分布 ...

  6. 【模板】解决二分图匹配的强力算法——Hopcroft-Karp算法

    详细解释 参见:http://blog.csdn.net/wall_f/article/details/8248373 简要过程 HK算法可以当成是匈牙利算法的优化版,和dinic算法的思想比较类似. ...

  7. jquery文档加载几种写法,图片加载写法

    jquery文档加载写法: $(function(){ }) ; //个人最常使用方式 $(document).ready(function(){ }); //调用文档对象下的ready方法传入一个函 ...

  8. java生成缩略图,旋转,水印,截图

    转自:http://rensanning.iteye.com/blog/1545708 感谢,方便自己查看

  9. HDU 2829 Lawrence(斜率优化DP O(n^2))

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2829 题目大意:有一段铁路有n个站,每个站可以往其他站运送粮草,现在要炸掉m条路使得粮草补给最小,粮草 ...

  10. 在写一次epoll

    epoll & select & poll只能处理IO相关的操作,epoll每一个操作必须注册到时间监控机制中,并且还需要进程或者线程进行管理. 多进程/多线程 和epoll相比较 e ...