题目

三棵带边权的树,求

\[dis1(u,v) + dis2(u,v) + dis3(u,v)
\]

的最大值

\(1 \le n \le 10^5\)

题解

  • 对\(T_1\)做边分治,把分治边的两边分别染成白色和黑色,设分治边权值为\(W\)距离变成:

    \[d1(u) + d1(v) + dis2(u,v) + dis3(u,v) + \ W
    \]

  • 将分治中心\(dfs\)到的所有点加入\(T2\)做虚树得到\(T2'\),\(dfs\)这颗虚树到\(p\)的时候统计所有\(p\)作为\(lca\)的情况:

    \[d1(u) + d1(v) + d2(u) + d2(v) + dis3(u,v) \ + W - 2dis(p)
    \]

  • 考虑在\(T_3\)中新建一个点\(u'\),以\(d1(u)+d2(u)\)的边权挂在$ u $下面(实现的时候不需要真的新建)

    现在后面两项都是定值了,只需要考虑在\(T_3'\)上找到端点异色的直径

    边权非负时合并直径,合并后的直径端点一定在合并前两条直径的端点里面

    那直接在\(dfs \ T_2'\) 的时候维护一下\(T_3'\)上同色的直径端点,然后再黑白组合即可

    就是有点长....

    #include<bits/stdc++.h>
    #define ll long long
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    using namespace std;
    const int N=200010;
    typedef pair<int,ll>pii;
    int n,st[N],tot,fg[N];
    ll d1[N],d2[N],d3[N],ans,W;
    char gc(){
    static char*p1,*p2,s[1000000];
    if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
    return(p1==p2)?EOF:*p1++;
    }
    ll rd(){
    ll x=0;char c=gc();
    while(c<'0'||c>'9')c=gc();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc();
    return x;
    }
    bool upd(ll&x,ll y){
    if(x>=y)return false;
    x=y;return true;
    }
    namespace T3{
    int o=1,hd[N],idx2,f[N][19],lg[N];
    int dep[N],bin[19],pos[N];
    struct Edge{int v,nt;ll w;}E[N<<1];
    void adde(int u,int v,ll w){
    E[o]=(Edge){v,hd[u],w};hd[u]=o++;
    E[o]=(Edge){u,hd[v],w};hd[v]=o++;
    }
    void dfs(int u,int fa){
    f[++idx2][0]=u;pos[u]=idx2;
    for(int i=hd[u];i;i=E[i].nt){
    int v=E[i].v;ll w=E[i].w;
    if(v==fa)continue;
    dep[v]=dep[u]+1;
    d3[v]=d3[u]+w;
    dfs(v,u);
    f[++idx2][0]=u;
    }
    }
    int Min(int x,int y){return dep[x]<dep[y]?x:y;}
    void init(){
    lg[0]=-1;for(int i=1;i<=idx2;++i)lg[i]=lg[i>>1]+1;
    for(int i=bin[0]=1;i<19;++i)bin[i]=bin[i-1]<<1;
    for(int i=1;i<19;++i)
    for(int j=1;j+bin[i]-1<=idx2;++j){
    f[j][i]=Min(f[j][i-1],f[j+bin[i-1]][i-1]);
    }
    }
    int lca(int u,int v){
    int x=pos[u],y=pos[v];
    if(x>y)swap(x,y);
    int t=lg[y-x+1];
    return Min(f[x][t],f[y-bin[t]+1][t]);
    }
    ll que(int u,int v){return d1[u]+d1[v]+d2[u]+d2[v]+d3[u]+d3[v]-d3[lca(u,v)]*2;}
    void solve(){dfs(1,0);init();}
    }
    namespace T2{
    int id[N],idx,idx2,sta[N],top,dep[N];
    int o=1,hd[N],f[N][19],bin[19],lg[N],pos[N];
    struct Edge{int v,nt;ll w;}E[N<<1];
    void adde(int u,int v,ll w){
    E[o]=(Edge){v,hd[u],w};hd[u]=o++;
    E[o]=(Edge){u,hd[v],w};hd[v]=o++;
    }
    void Adde(int u,int v){
    E[o]=(Edge){v,hd[u],0};hd[u]=o++;
    E[o]=(Edge){u,hd[v],0};hd[v]=o++;
    }
    int Min(int x,int y){return dep[x]<dep[y]?x:y;}
    void dfs1(int u,int fa){
    id[u]=++idx;
    f[++idx2][0]=u;pos[u]=idx2;
    for(int i=hd[u];i;i=E[i].nt){
    int v=E[i].v;ll w=E[i].w;
    if(v==fa)continue;
    dep[v]=dep[u]+1;
    d2[v]=d2[u]+w;
    dfs1(v,u);
    f[++idx2][0]=u;
    }
    }
    void init(){
    lg[0]=-1;for(int i=1;i<=idx2;++i)lg[i]=lg[i>>1]+1;
    for(int i=bin[0]=1;i<19;++i)bin[i]=bin[i-1]<<1;
    for(int i=1;i<19;++i)
    for(int j=1;j+bin[i]-1<=idx2;++j){
    f[j][i]=Min(f[j][i-1],f[j+bin[i-1]][i-1]);
    }
    }
    int lca(int u,int v){
    int x=pos[u],y=pos[v];
    if(x>y)swap(x,y);
    int t=lg[y-x+1];
    return Min(f[x][t],f[y-bin[t]+1][t]);
    }
    void solve(){
    dfs1(1,0);init();
    sta[++top]=1;
    }
    ll cal(int u,int v){
    return (!u&&!v) ? -2 : (!u||!v) ? -1 : T3::que(u,v);
    }
    struct data{
    int x,y;ll v;
    data(int _x=0,int _y=0,ll _v=0):x(_x),y(_y),v(_v){};
    void init(){x=y=0;v=-2;}
    data operator +(const data&A)const{
    data re=v>A.v?*this:A;
    if(upd(re.v,cal(x,A.x)))re=data(x,A.x,re.v);
    if(upd(re.v,cal(x,A.y)))re=data(x,A.y,re.v);
    if(upd(re.v,cal(y,A.x)))re=data(y,A.x,re.v);
    if(upd(re.v,cal(y,A.y)))re=data(y,A.y,re.v);
    return re;
    }
    ll operator *(const data&A)const{
    ll re=0;
    upd(re,cal(x,A.x));
    upd(re,cal(x,A.y));
    upd(re,cal(y,A.x));
    upd(re,cal(y,A.y));
    return re;
    }
    }L[N],R[N];
    void dfs2(int u,int fa){
    L[u].init();R[u].init();
    if(fg[u]&1)L[u].x=u,L[u].v++;
    else if(fg[u])R[u].x=u,R[u].v++;
    for(int i=hd[u];i;i=E[i].nt){
    int v=E[i].v;
    if(v==fa)continue;
    dfs2(v,u);
    upd(ans,max(L[u]*R[v],R[u]*L[v])-2*d2[u]+W);
    L[u]=L[u]+L[v];R[u]=R[u]+R[v];
    }
    }
    bool cmp(int a,int b){return id[a]<id[b];}
    void query(){
    o=1;sort(st+1,st+tot+1,cmp);
    hd[1]=0;for(int i=1;i<=tot;++i)hd[st[i]]=0;
    for(int i=1;i<=tot;++i){
    if(st[i]==sta[top])continue;
    int u=st[i],w=lca(u,sta[top]);
    if(w==sta[top]){sta[++top]=u;continue;}
    while(top>1&&dep[sta[top-1]]>=dep[w])Adde(sta[top-1],sta[top]),top--;
    if(w!=sta[top])hd[w]=0,Adde(w,sta[top--]),sta[++top]=w;
    sta[++top]=u;
    }
    while(top>1)Adde(sta[top-1],sta[top]),top--;
    dfs2(1,0);
    }
    }
    namespace T1{
    int o,hd[N],cnt,size,vis[N<<1],rt,mn,sz[N];
    vector<pii>g[N];
    struct Edge{int v,nt;ll w;}E[N<<1];
    void adde(int u,int v,ll w){
    g[u].pb(mk(v,w));
    g[v].pb(mk(u,w));
    }
    void Adde(int u,int v,ll w){
    E[o]=(Edge){v,hd[u],w};hd[u]=o++;
    E[o]=(Edge){u,hd[v],w};hd[v]=o++;
    // cerr<<u<<" "<<v<<" "<<w<<endl;
    }
    void dfs(int u,int fa){
    for(int i=0,lst=0;i<(int)g[u].size();++i){
    int v=g[u][i].fi;ll w=g[u][i].se;
    if(v==fa)continue;dfs(v,u);
    if(!lst){Adde(u,v,w);lst=u;continue;}
    Adde(lst,++cnt,0);Adde(cnt,v,w);lst=cnt;
    }
    }
    void getrt(int u,int fa){
    sz[u]=1;
    for(int i=hd[u];~i;i=E[i].nt){
    int v=E[i].v;
    if(v==fa||vis[i])continue;
    getrt(v,u);sz[u]+=sz[v];
    int tmp=max(sz[v],size-sz[v]);
    if(!~rt||tmp<mn)mn=tmp,rt=i;
    }
    }
    void cal(int u,int fa,int F){
    if(u<=n)fg[st[++tot]=u]=F;
    for(int i=hd[u];~i;i=E[i].nt){
    int v=E[i].v;ll w=E[i].w;
    if(v==fa||vis[i])continue;
    d1[v]=d1[u]+w;
    cal(v,u,F);
    }
    }
    void divide(int i){
    if(size==1)return;
    vis[i]=vis[i^1]=1;
    int p=E[i].v,q=E[i^1].v;
    tot=0;
    d1[p]=0;cal(p,0,1);
    d1[q]=0;cal(q,0,2);
    W=E[i].w;T2::query();
    for(int j=1;j<=tot;++j)fg[st[j]]=0;
    int t1=sz[p]<sz[q]?sz[p]:size-sz[q];
    int t2=size-t1;
    rt=-1;size=t1;
    getrt(p,0);
    divide(rt);
    rt=-1;size=t2;
    getrt(q,0);
    divide(rt);
    }
    void solve(){
    for(int i=1;i<=n<<1;++i)hd[i]=-1;
    cnt=n;dfs(1,0);
    rt=-1;size=cnt;
    getrt(1,0);
    divide(rt);
    }
    }//
    int main(){
    #ifndef ONLINE_JUDGE
    freopen("access.in","r",stdin);
    freopen("access.out","w",stdout);
    #endif
    n=rd();int u,v;ll w;
    for(int i=1;i<n;++i){
    u=rd(),v=rd(),w=rd();
    T1::adde(u,v,w);
    }
    for(int i=1;i<n;++i){
    u=rd(),v=rd(),w=rd();
    T2::adde(u,v,w);
    }
    for(int i=1;i<n;++i){
    u=rd(),v=rd(),w=rd();
    T3::adde(u,v,w);
    }
    T3::solve();
    T2::solve();
    T1::solve();
    cout<<ans<<endl;
    return 0;
    }

【loj2339】【WC2018】通道的更多相关文章

  1. [WC2018]通道——边分治+虚树+树形DP

    题目链接: [WC2018]通道 题目大意:给出三棵n个节点结构不同的树,边有边权,要求找出一个点对(a,b)使三棵树上这两点的路径权值和最大,一条路径权值为路径上所有边的边权和. 我们按照部分分逐个 ...

  2. $[WC2018]$通道(虚树,边分练习)

    \([WC2018]\)通道(虚树,边分练习) 感受码题的快感 这段时间真的是忙忙忙忙忙,省选之前还是露个脸,免得以后没机会了. 但是我感觉我的博客真的没啥人看,虽然我挺想要有人看的,但是自己真的没啥 ...

  3. [WC2018]通道

    题目描述 http://uoj.ac/problem/347 题解 解法1 求三棵树的直径,看起来非常不可做,但是所有边权都是正的,可以让我们想到爬山. 所以我们可以按照BFS求树的直径的方法,随机一 ...

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

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

  5. 洛谷P4220 [WC2018]通道(边分治+虚树)

    题面 传送门 题解 代码不就百来行么也不算很长丫 虽然这题随机化贪心就可以过而且速度和正解差不多不过我们还是要好好学正解 前置芝士 边分治 米娜应该都知道点分治是个什么东西,而边分治,顾名思义就是对边 ...

  6. bzoj5152 [Wc2018]通道

    题目链接 正解:不会做. 写一个爬山算法就过官方数据了(逃 具体来说就是每次随机一个根,然后迭代找最长路的那个点. 多随机几次取$max$就行了.正解以后再补.. #include <bits/ ...

  7. [WC2018]通道(乱搞,迭代)

    [洛谷题面]https://www.luogu.org/problemnew/show/P4221 这个题以及[CTSC2018 暴力写挂]都有类似的乱搞做法能通过考场数据. 具体搞法就是随一个起点, ...

  8. ZJOI2019一轮停课刷题记录

    Preface 菜鸡HL终于狗来了他的省选停课,这次的时间很长,暂定停到一试结束,不过有机会二试的话还是可以搞到4月了 这段时间的学习就变得量大而且杂了,一般以刷薄弱的知识点和补一些新的奇怪技巧为主. ...

  9. WC 2018 题解

    WC 2018 题解 一些感受.jpg 题目难度相较前些年会相对简单一点?(FAKE.jpg 平均码量符合WC风格?(甚至更多一点 出题人良心! [WC2018] 通道 一个不知道对不对的$\log ...

  10. 仙人掌&圆方树

    仙人掌&圆方树 Tags:图论 [x] [luogu4320]道路相遇 https://www.luogu.org/problemnew/show/P4320 [ ] [SDOI2018]战略 ...

随机推荐

  1. Django中ORM过滤时objects.filter()无法对月份过滤

    django中的filter日期查询属性有:year.month.day.week_day.hour.minute.second 在做复习博客项目时,我把项目从linux移到了windows,然后博客 ...

  2. WPF 很少人知道的科技

    原文:WPF 很少人知道的科技 本文介绍不那么常见的 WPF 相关的知识. 本文内容 在 C# 代码中创建 DataTemplate 多个数据源合并为一个列表显示 使用附加属性做缓存,避免内存泄漏 使 ...

  3. java基础 Math

    package cn.mantishell.day08.demo04; /** * java.util.Math类是数学相关的工具类,里面提供类大量的静态方法,完成与数学运算相关的操作 * * pub ...

  4. 学习笔记—log4net

    一.log4net.dll下载地址:http://logging.apache.org/log4net/download_log4net.cgi 二.在项目中引用log4net.dll 三.设置在程序 ...

  5. django.db.utils.InternalError: (1060, "Duplicate column name 'user_id'")迁移报错解决方法

    django.db.utils.InternalError: (1060, "Duplicate column name 'user_id'")迁移报错解决方法 django.db ...

  6. Python进阶----数据库的基础,关系型数据库与非关系型数据库(No SQL:not only sql),mysql数据库语言基础(增删改查,权限设定)

    day37 一丶Python进阶----数据库的基础,mysql数据库语言基础(增删改查,权限设定) 什么是数据库:    简称:DataBase ---->DB    数据库即存放数据的仓库, ...

  7. python基础之猜数字游戏

    #猜数字游戏 import random #impor语句导入random模块 guessor=0; print("#"*30) #输出30个”#“(”############## ...

  8. vue-quill-edito 字体倾斜加粗无效

    长话短说,出现这种情况的原因80%-90%的概率在你项目里面有一个全局的 一般在reset.css重置文件中 font-weight:normal; font-style:normal; font-s ...

  9. JavaScript之控制标签属性

    var pic=document.getElementById('pic'); var obtn=document.getElementById('btn'); console.log(pic.get ...

  10. 结对编程(-java实现)

    一 .Github项目地址:https://github.com/mushan520/Four-fundamental-rules-java.git                           ...