zoukankan      html  css  js  c++  java
  • [CTSC2018]暴力写挂

    题目描述

    www.lydsy.com/JudgeOnline/upload/201805/day1(1).pdf

    题解

    首先来看这个我们要最大化的东西。

    deep[u]+deep[v]-deep[lca(u,v)]-deep[lca(u',v')]

    后面的那个东西看起来不太合群,我们可以把前后拆开。

    deep[u]+deep[v]-deep[lca(u,v)]

    我们发现这其实就是u到根的链和v到根的链的并。

    然后它还等于(deep[u]+deep[v]+dis[u][v])/2

    因为deep数组我们可以直接求出,所以我们就把一颗有根树上的问题放到了无根树上,也就是可以去掉lca的影响了。

    然后考虑枚举第二颗树的LCA,那么一组合法的点应当在这个点的两颗不同的子树中。

    然后对第一棵树边分,发现这颗边分树也是一颗二叉树,每个叶子结点代表原树上的一个点。

    于是这题的做法来了,我们在dfs第二颗树的时候,像线段树合并一样合并边分树,因为不管叶子的情况下,每个节点都代表一条边,每条边连接着两个点。

    这样我们对这个点记一个lans和rans分别代表左端点的最优答案和右端点的最优答案。

    维护答案的形式为deep[x]+dis(x,edge)

    合并的时候顺带计算答案。

    注意,要考虑u和v重合的情况。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define inf 1e18
    #define N 740009
    using namespace std;
    typedef long long ll;
    ll lans[N*23],rans[N*23],ans,dis[N],deep[N][20],nowdeep,val[N*5];
    int atp,size[N],sum,nowroot,root,ha,finaldep[N];
    int fa[N*5],ls[N*5],rs[N*5],tr[N*23][2],dian,T[N],n,id[N*23];
    bool jin[N<<1];
    inline ll rd(){
        ll x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }
    struct tu{
        int head[N],tot;
        struct edge{int n,to;ll l;}e[N<<1];
        void clear(){memset(head,0,sizeof(head));tot=0;} 
        inline void add(int u,int v,ll l){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;e[tot].l=l;}
    }E[2];
    struct node{int n,to;ll l;}e[N<<2];
    int head[N<<1],tot=1;
    inline void add(int u,int v,ll l){
       e[++tot].n=head[u];e[tot].to=v;head[u]=tot;e[tot].l=l;
       e[++tot].n=head[v];e[tot].to=u;head[v]=tot;e[tot].l=l;
    }
    void dfs1(int u,int fa){
        int now=0;
        for(int i=E[0].head[u];i;i=E[0].e[i].n)if(E[0].e[i].to!=fa){
            int v=E[0].e[i].to;dis[v]=dis[u]+E[0].e[i].l;
            if(!now){add(u,v,E[0].e[i].l);now=u;}
            else{++atp;add(now,atp,0);add(atp,v,E[0].e[i].l);now=atp;}
            dfs1(v,u);
        }
    }
    void getroot(int u,int fa){
        size[u]=1;
        for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa&&!jin[i]){
            int v=e[i].to;
            getroot(v,u);
            size[u]+=size[v];
            if(max(size[v],sum-size[v])<nowroot){root=i;nowroot=max(size[v],sum-size[v]);ha=size[v];}
        }
    }
    void getdeep(int u,int fa,int dep){
        for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa&&!jin[i]){
            int v=e[i].to;
            deep[v][dep]=deep[u][dep]+e[i].l;
            getdeep(v,u,dep);
        }
    }
    int solve(int u,int s,int dep){
        if(s==1){finaldep[u]=dep;return u;} 
        int now=++atp;
        root=atp+1;nowroot=atp;sum=s;
        getroot(u,0);
        jin[root]=jin[root^1]=1;
        int x=e[root].to,y=e[root^1].to,xs=ha,ys=s-ha;val[atp]=e[root].l;
        getdeep(x,y,dep);getdeep(y,x,dep);
        fa[ls[now]=solve(x,xs,dep+1)]=now;fa[rs[now]=solve(y,ys,dep+1)]=now;
        return now;
    }
    inline int ins(int x){
        int now=x,pre=0;
        for(int i=finaldep[x];i;--i){
            ++dian;id[dian]=fa[now];lans[dian]=rans[dian]=-inf;
            if(ls[fa[now]]==now)lans[dian]=dis[x]+deep[x][i-1],tr[dian][0]=pre;
            if(rs[fa[now]]==now)rans[dian]=dis[x]+deep[x][i-1],tr[dian][1]=pre;
            pre=dian;now=fa[now];
        }
        return dian;
    }
    inline int merge(int x,int y){
        if(!x||!y)return x^y;
        ans=max(ans,(lans[x]+rans[y]+val[id[x]])/2-nowdeep);
        ans=max(ans,(rans[x]+lans[y]+val[id[x]])/2-nowdeep);
        lans[x]=max(lans[x],lans[y]);rans[x]=max(rans[x],rans[y]);
        tr[x][0]=merge(tr[x][0],tr[y][0]);tr[x][1]=merge(tr[x][1],tr[y][1]);
        return x;
    }
    void dfs2(int u,int fa,ll d){
        T[u]=ins(u);
        ans=max(ans,dis[u]-d);
        for(int i=E[1].head[u];i;i=E[1].e[i].n)if(E[1].e[i].to!=fa){
            int v=E[1].e[i].to;
            dfs2(v,u,d+E[1].e[i].l);nowdeep=d;
            T[u]=merge(T[u],T[v]);
        }
    }
    int main(){
        n=rd();int u,v;ll w;ans=-inf;
        for(int i=1;i<n;++i){u=rd();v=rd();w=rd();E[0].add(u,v,w);E[0].add(v,u,w);}
        for(int i=1;i<n;++i){u=rd();v=rd();w=rd();E[1].add(u,v,w);E[1].add(v,u,w);}
        atp=n;dfs1(1,0);
        solve(1,atp,0);
        dfs2(1,0,0);
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    Bootstrap组件福利篇 网址
    <a>标签中的href="javascript:;"
    HTTP请求上下文之终结:HttpContext类
    数据库分离 附加 sqlserver
    C#中三层架构UI、BLL、DAL、Model实际操作(转)
    比较好的网上的sqlserver读书笔记
    ORACLE重建索引详解
    SQL Server遍历表的几种方法(转)
    提高数据库操作的效率(转)
    哈希表Hashtable与字典表Dictionary<K,V>的比较。
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10371766.html
Copyright © 2011-2022 走看看