• [WC2018]通道


     [WC2018]通道 

    爽到爽到爽到爽到爽到爽到爽到爽到爽到爽到爽到爽到爽到一遍AC

    但是题目太神主要还是为了锻炼码力

    3棵树,考虑层层处理,互相考虑

    第一棵

    边分治。儿子少。虚边权值为0。

    统计在第一棵树上跨过中心边的点对

    找到d1,到中心边距离。两个点第一个距离已经可以计算

    左部为L,右部为R。

    下面以这个为基础统计

    第二棵

    第二棵第三棵的结构无法掌握。要具体一些。

    所以虚树,对于当前边分治的点集建第二棵树上的虚树

    第二棵树上两点距离?dis+dis-lca!

    枚举LCA,统计一个属于L的,一个属于R的,并且第二棵树上的虚树LCA是x的点对

    已经可以做两棵树的了。

    第三棵

    虚树合并的时候,本质是考虑两个子树的备选集合进行合并,但是取max,所以我们只保留了最大的。

    我们直接考虑dis是怎么来的:V+d1[x]+d1[y]+d2[x]+d2[y]-2*d2[lca(x,y)]+dis3(x,y)

    2*d2[lca(x,y)]我们正在枚举lca,V,分治树中心边权值是定值

    所以,我们要从L中选择x,R中选择y,最大化(d1[x]+d2[x])+(d1[y]+d2[y])+dis3(x,y)

    记录一个没有最优子结构了。所以考虑记录集合

    树形DP本质是集合合并,如果我们知道合并后的集合放在T3上的最大值,就可以更新答案

    集合当然是无法记录的,但是我们只关心“(d1[x]+d2[x])+(d1[y]+d2[y])+dis3(x,y)”的最大值

     

    结论:

    都是正边权正权点,两个集合合并之后,dis的最大值,就是原来四个端点两两最大值

    所以L或者R的备选集合记录最长dis的端点,先L,R或者R,L贡献答案,再从儿子合并L或者R

    开f[x][1/2],记录来自L,R子集的集合的端点

    然后没了

    代码

    细节:
    1.LCA用ST表O(1)做,是欧拉遍历序,预处理时候注意i+(1<<j)-1<=lim

    2.多开namespace。。。

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=2e5+5;
    int n;int lg[2*N];int mem[N],num;//set of L and R
    ll ans;ll d1[N],d2[N],d3[N];
    int be[N];//L : 1 or R : 2
    ll V;
    namespace t3{
    struct node{
        int nxt,to;ll w;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y,ll z){e[++cnt].nxt=hd[x];e[cnt].w=z;e[cnt].to=y;hd[x]=cnt;}
    int dfn[N],dfn2[N];int dep[N],g[2*N][20];int id[2*N],df;
    void dfs(int x,int fa,int d){
        id[++df]=x;dep[x]=d;
        dfn[x]=df;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;if(y==fa)continue;
            d3[y]=d3[x]+e[i].w;
            dfs(y,x,d+1);id[++df]=x;
        }
        dfn2[x]=df;
    }    
    int lca(int x,int y){
        if(dfn[x]>dfn[y]) swap(x,y);int len=dfn[y]-dfn[x]+1;len=lg[len];x=dfn[x],y=dfn[y];//warning!!
        if(dep[g[x][len]]<dep[g[y-(1<<len)+1][len]]) return g[x][len];return g[y-(1<<len)+1][len];
    }
    ll dis(int x,int y){
        return d1[x]+d2[x]+d1[y]+d2[y]+d3[x]+d3[y]-1LL*2*d3[lca(x,y)];
    }
    void build(){
        int x,y;ll z;
        for(reg i=1;i<n;++i) rd(x),rd(y),rd(z),add(x,y,z),add(y,x,z);
        dfs(1,0,1);
        for(reg i=1;i<=df;++i) g[i][0]=id[i];
        for(reg j=1;j<=18;++j){
            for(reg i=1;(i+(1<<j)-1)<=df;++i){
                if(dep[g[i][j-1]]<dep[g[i+(1<<(j-1))][j-1]]) g[i][j]=g[i][j-1];
                else g[i][j]=g[i+(1<<(j-1))][j-1];
            }
        }
    }
    
    }
    ///////////////////////////////////////////////////////////////////////////////////////////T3T3T3T3T3T3
    namespace t2{
    struct node{
        int nxt,to;ll w;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y,ll z){e[++cnt].nxt=hd[x];e[cnt].w=z;e[cnt].to=y;hd[x]=cnt;}
    int dfn[N],dfn2[N];int dep[N],g[2*N][20];int id[2*N],df;
    void dfs(int x,int fa,int d){
        id[++df]=x;dep[x]=d;
        dfn[x]=df;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;if(y==fa)continue;
            d2[y]=d2[x]+e[i].w;
            dfs(y,x,d+1);id[++df]=x;
        }
        dfn2[x]=df;
    }    
    int lca(int x,int y){
        if(dfn[x]>dfn[y]) swap(x,y);int len=dfn[y]-dfn[x]+1;len=lg[len];x=dfn[x],y=dfn[y];//warning!!
        if(dep[g[x][len]]<dep[g[y-(1<<len)+1][len]]) return g[x][len];return g[y-(1<<len)+1][len];
    }
    void build(){
        int x,y;ll z;
        for(reg i=1;i<n;++i) rd(x),rd(y),rd(z),add(x,y,z),add(y,x,z);
        dfs(1,0,1);
        for(reg i=1;i<=df;++i) g[i][0]=id[i];
        for(reg j=1;j<=18;++j){
            for(reg i=1;(i+(1<<j)-1)<=df;++i){
                if(dep[g[i][j-1]]<dep[g[i+(1<<(j-1))][j-1]]) g[i][j]=g[i][j-1];
                else g[i][j]=g[i+(1<<(j-1))][j-1];
            }
        }
        memset(hd,0,sizeof hd);//warning!!!
        cnt=0;//warning!!!
    }
    int sta[N],top;
    pair<int,int>f[N][3];
    int tmp[10];
    ll calc(pair<int,int>A,pair<int,int>B){//for ans
        if(A.fi==0&&A.se==0) return 0;//empty
        else if(B.fi==0&&B.se==0) return 0;
        return max(t3::dis(A.fi,B.fi),max(t3::dis(A.se,B.fi),max(t3::dis(A.fi,B.se),t3::dis(A.se,B.se))));
    }
    pair<int,int>merge(pair<int,int>A,pair<int,int>B){
        if(A.fi==0&&A.se==0) return B;//empty
        else if(B.fi==0&&B.se==0) return A;
        
        int lp=0;
        pair<int,int>ret;
        ll mx=-233;
        tmp[++lp]=A.fi,tmp[++lp]=A.se;
        tmp[++lp]=B.fi,tmp[++lp]=B.se;
        for(reg i=1;i<=lp-1;++i){
            for(reg j=i+1;j<=lp;++j){
                ll now=t3::dis(tmp[i],tmp[j]);
                if(now>mx){
                    mx=now;ret.fi=tmp[i];ret.se=tmp[j];
                }
            }
        }
        return ret;
    }
    void dp(int x){//first add x
        if(be[x]){
            f[x][be[x]].fi=x;f[x][be[x]].se=x;
        }
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            dp(y);
            ans=max(ans,max(calc(f[x][1],f[y][2]),calc(f[x][2],f[y][1]))-1LL*d2[x]*2+V);
            f[x][1]=merge(f[x][1],f[y][1]);
            f[x][2]=merge(f[x][2],f[y][2]);
        }
    }
    bool cmp(int x,int y){
        return dfn[x]<dfn[y];
    }
    void wrk(){//build xushu and DP
        sort(mem+1,mem+num+1,cmp);
        int lp=num;
        for(reg i=1;i<lp;++i){
            mem[++num]=lca(mem[i],mem[i+1]);
        }
        sort(mem+1,mem+num+1,cmp);
        num=unique(mem+1,mem+num+1)-mem-1;
        top=0;
        for(reg i=1;i<=num;++i){
            while(top&&(!(dfn2[sta[top]]>=dfn2[mem[i]]))) --top;
            if(top) add(sta[top],mem[i],0);
            sta[++top]=mem[i];
        }
        dp(mem[1]);
        //clear!!!!
        for(reg i=1;i<=num;++i) {
            int x=mem[i];
            be[x]=0,hd[x]=0,d1[x]=0,f[x][1].fi=0,f[x][1].se=0;
            f[x][2].fi=0;f[x][2].se=0;
        }
        top=0;cnt=0;
    }    
    
    }
    ////////////////////////////////////////////////////////////////////////////////////////T2T2T2T2T2T2T2T2T2T2T2T2
    namespace t1{
    struct node{
        int nxt,fr,to;ll w;
    }e[2*N];
    int hd[N],cnt=1;
    bool vis[2*N];
    void add(int x,int y,ll z){e[++cnt].nxt=hd[x];e[cnt].w=z;e[cnt].to=y;e[cnt].fr=x;hd[x]=cnt;}
    vector<pair<int,ll> >to[N];
    bool exi[N];//is or not true point
    int cur;
    void rebuild(int x,int fa){
        exi[x]=1;int las=0;
        for(reg i=0;i<(int)to[x].size();++i){
            int y=to[x][i].fi;
            if(y==fa) continue;
            if(!las){
                add(x,y,to[x][i].se);
                add(y,x,to[x][i].se);
                las=x;
            }else{
                ++cur;add(las,cur,0);add(cur,las,0);
                add(cur,y,to[x][i].se);add(y,cur,to[x][i].se);
                las=cur;
            }
            rebuild(y,x);
        }
    }
    int nowsz,rt;
    int mi;
    int sz[N];
    void dfs(int x,int fa){
        sz[x]=1;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa||vis[i]) continue;
            dfs(y,x);sz[x]+=sz[y];
            if(max(sz[y],nowsz-sz[y])<mi){
                mi=max(sz[y],nowsz-sz[y]);
                rt=i;
            }
        }
    }
    void dfs2(int x,int fa,int typ){//exi!!!
        sz[x]=1;
        if(exi[x]) mem[++num]=x,be[x]=typ;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa||vis[i]) continue;
            d1[y]=d1[x]+e[i].w;
            dfs2(y,x,typ);
            sz[x]+=sz[y];
        }
    }
    
    void divi(int x){
        if(nowsz==1) return;
        rt=0;
        mi=0x3f3f3f3f;
        dfs(x,0);
        int L=e[rt].fr,R=e[rt].to;//L is R 's fa
        vis[rt]=vis[rt^1]=1;
        
        num=0;
        d1[L]=0,d1[R]=0;
        dfs2(L,R,1);dfs2(R,L,2);
        V=e[rt].w;
        t2::wrk();
        
        nowsz=nowsz-sz[R];
        divi(L);
        nowsz=sz[R];
        divi(R);
    }
    void build(){
        int x,y;ll z;
        for(reg i=1;i<n;++i){// ,add(x,y,z),add(y,x,z);
            rd(x),rd(y),rd(z);to[x].push_back(mk(y,z));
            to[y].push_back(mk(x,z));
        }
        cur=n;
        rebuild(1,0);
    }
    void sol(){
        nowsz=cur;
        divi(1);
    }
    
    }
    int main(){
        rd(n);lg[0]=0;
        for(reg i=1;i<=2*n;++i) lg[i]=(i>>(lg[i-1]+1))?lg[i-1]+1:lg[i-1];
        t1::build();
        t2::build();
        t3::build();
        t1::sol();printf("%lld",ans);return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/3/29 11:09:48
    */
    View Code

    一句话总结就是:

    以“第一棵树跨越中心边LR集合、第二棵树虚树LCA处”为标准,利用“备选集合在第三棵树上最大值”的一个性质,进行统计。

     

  • 相关阅读:
    2-红帽RHEL 7起步
    1-了解开源共享精神
    5.pip安装时使用国内源,加快下载速度
    4. python-运算符(另类语法)
    海燕python学习目录,特别棒!
    1Python学习CentOS 7 Linux环境搭建
    2python脚本在window编辑后linux不能执行的问题
    3Python脚本在linux环境下头文件解释
    5G 频谱 新技术
    python -实现单例模式五种方法
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10622138.html
Copyright © 2020-2023  润新知