[UOJ347]通道
锟题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]通道的更多相关文章
- 【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\)两点 ...
- UOJ347 WC2018 通道 边分治、虚树
传送门 毒瘤数据结构题qwq 设三棵树分别为$T1,T2,T3$ 先将$T1$边分治,具体步骤如下: ①多叉树->二叉树,具体操作是对于每一个父亲,建立与儿子个数相同的虚点,将父亲与这些虚点穿成 ...
- Paypal开发中遇到请求被中止: 未能创建 SSL/TLS 安全通道及解决方案
最近在基于ASP.NET上开发了Paypal支付平台,在ASP.NET开发的过程中没有遇到这个问题,但是引用到MVC开发模式中的时候就出现了"未能创建 SSL/TLS 安全通道及解决方案&q ...
- JAVA NIO Socket通道
DatagramChannel和SocketChannel都实现定义读写功能,ServerSocketChannel不实现,只负责监听传入的连接,并建立新的SocketChannel,本身不传输数 ...
- 学习 opencv---(4) 分离颜色通道 && 多通道混合
上篇文章中我们讲到了使用addWeighted函数进行图像混合操作,以及将ROI和addWeighted函数结合起来使用,对指定区域进行图像混合操作. 而为了更好地观察一些图像材料的特征,有时需要对R ...
- 关于QImage提取单色通道方法(vector)
转载请标明处: 作者:微微苏荷 本文地址:关于QImage提取单色通道方法(vector) 近日,用QT和mxnet结合做一个图像识别的demo.遇到需要把图片从QImage转为vector单色分离的 ...
- 基于暗通道优先算法的去雾应用(Matlab/C++)
基于暗通道优先的单幅图像去雾算法(Matlab/C++) 算法原理: 参见论文:Single Image Haze Removal Using Dark Channel Pri ...
- Java NIO4:Socket通道
Socket通道 上文讲述了通道.文件通道,这篇文章来讲述一下Socket通道,Socket通道与文件通道有着不一样的特征,分三点说: 1.NIO的Socket通道类可以运行于非阻塞模式并且是可选择的 ...
- Java NIO3:通道和文件通道
通道是什么 通道式(Channel)是java.nio的第二个主要创新.通道既不是一个扩展也不是一项增强,而是全新的.极好的Java I/O示例,提供与I/O服务的直接连接.Channel用于在字节缓 ...
随机推荐
- HDU 1203 I NEED A OFFER! (dp)
题目链接 Problem Description Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了.要申请国外的任何大学,你都要交纳一定 ...
- python keras YOLOv3实现目标检测
1.连接 https://www.jianshu.com/p/3943be47fe84
- bzoj 2730 割点
首先我们知道,对于这张图,我们可以枚举坍塌的是哪个点,对于每个坍塌的点,最多可以将图分成若干个不连通的块,这样每个块我们可能需要一个出口才能满足题目的要求,枚举每个坍塌的点显然是没有意义的,我们只需要 ...
- windows 上启动appium
import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecuteResultHandl ...
- Java 关于微信公众号支付总结附代码
很多朋友第一次做微信支付的时候都有蒙,但当你完整的做一次就会发现其实并没有那么难 业务流程和应用场景官网有详细的说明:https://pay.weixin.qq.com/wiki/doc/api/js ...
- centos_7.1.1503_src_5
http://vault.centos.org/7.1.1503/os/Source/SPackages/ minicom-2.6.2-5.el7.src.rpm 05-Jul-2014 13:50 ...
- 004 ConcurrentHashMap原理
下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为 ...
- TensorFlow计算模型—计算图
TensorFlow是一个通过计算图的形式来表述计算的编程系统.其中的Tnesor,代表它的数据结构,而Flow代表它的计算模型.TensorFlow中的每一个计算都是计算图上的一个节点,而节点之间的 ...
- linux sort排序命令
1 sort的工作原理 sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出. 2 sort的-u选项 在输出行中去除重复行. $ ...
- vim的各种tips
centos系统,修改vim的配置文件 /etc/vimrc 添加如下内容: 1) 打开 vimrc ,添加以下语句来使得语法高亮显示: syntax on 2) 如果此时语法还是没有高亮显示,那么在 ...