zoukankan      html  css  js  c++  java
  • 「WC2018」通道

    没有代码能力...

    LOJ #2339

    Luogu P4220

    UOJ #347


    题意

    给定三棵树$ T1,T2,T3$,求一个点对$ (x,y)$使得$ T1.dist(x,y)+T2.dist(x,y)+T3.dist(x,y)$最大

    每棵树的点数为$ 10^5$,时限$ 4s$


    $ Solution$

    尝试对$ T1$边分治 

    设当前分治到边$(L,R)$

    将$ L$及$ L$所在一侧的点染黑,将$ R$及$ R$所在一侧的点染白

    问题转化为找到一个点对$ (x,y)$使得满足$ x$为黑点$ y$为白点

    并且最大化

    $ T1.dist(x,L)+T1.dist(y,R)+len(x,y)+T2.dist(x,y)+T3.dist(x,y)$

    考虑将所有黑白点拿出来在$ T2$上构一棵虚树

    在虚树上$ DP$

    有一些不那么显然的性质:

     

    设两端均为黑色的最长路径的两个端点为$ (B1,B2)$,两端均为白色的最长路径的两个端点为$ (W1,W2)$

    则两端异色的最长路径的两个端点一定在$ B1,B2,W1,W2$中出现过

     

    设点集$ S$的黑色最长路径的两个端点为$ (B1,B2)$,点集$ T$的黑色最长路径的两个端点为$ (B3,B4)$

    则点集$ S cup T$的黑色最长路径的两个端点一定在$ B1,B2,B3,B4$中出现过

     

    用这两个性质就可以在虚树上$ DP$了

    形象化地,设我们在虚树上枚举点对在$ T2$上的$ LCA$

    则这个点对一定来自于枚举的$ LCA$的不同子树

    在每个子树记录黑色/白色最长路径的端点然后合并转移即可

    时间复杂度$ O(n log^2 n)$


    $my code$

    #include<ctime>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #define M 500010
    #define rt register int
    #define ll long long
    using namespace std;
    namespace fast_IO{
        const int IN_LEN=10000000,OUT_LEN=10000000;
        char ibuf[IN_LEN],*ih=ibuf+IN_LEN,*lastin=ibuf+IN_LEN;
        inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
    }
    using namespace fast_IO;
    #define getchar() getchar_()
    inline ll read(){
        ll x=0;char zf=1;char ch=getchar();
        while(ch!='-'&&!isdigit(ch))ch=getchar();
        if(ch=='-')zf=-1,ch=getchar();
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();return x*zf;
    }
    void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);}
    void writeln(const ll y){write(y);putchar('
    ');}
    int k,m,n,x,y,z,cnt,B,W,la;ll ans;
    int sorttable[M];ll dist[M];
    bool cmp(int x,int y){return sorttable[x]<sorttable[y];}
    int sz[M],A[M],col[M];bool vis[M];
    int nowmin,all,ed,sum,Root;
    struct node{int a;ll c;};
    vector<node>e[M];
    struct tree{
        int F[M],L[M],N[M],a[M],dfn[M],q[M],size[M],k=1,t=0,cnt=0;ll deep[M],c[M];
        int st[19][M],fa[M],lg2[M],fir[M],dep[M];
        void clear(){
            for(rt i=2;i<=k;i++)F[a[i]]=0,N[i]=0;
            F[Root]=0;k=1;t=0;cnt=0;
        }
        void add(int x,int y,ll z){
            a[++k]=y;c[k]=z;
            if(!F[x])F[x]=k;
            else N[L[x]]=k;
            L[x]=k;
        }
        void dfs(int x,int pre){
            q[++t]=x;dfn[x]=++cnt;size[x]=1;fa[x]=pre;fir[x]=t;
            for(rt i=F[x];i;i=N[i])if(a[i]!=pre){
                deep[a[i]]=deep[x]+c[i];
                dep[a[i]]=dep[x]+1;
                dfs(a[i],x);
                size[x]+=size[a[i]];
                q[++t]=x;
            }
        }
        
        void rebuild_init(int x,int pre){
            for(rt i=F[x];i;i=N[i])if(a[i]!=pre){
                e[x].push_back({a[i],c[i]});
                rebuild_init(a[i],x);
            }
        }
        void rebuild(){
            clear();
            for(rt i=1;i<=n;i++){
                if(e[i].size()<=2)for(auto j:e[i])add(i,j.a,j.c*(j.a<=la)),add(j.a,i,j.c*(j.a<=la));
                else {
                    int v1=++n,v2=++n;
                    add(i,v1,0);add(v1,i,0);add(i,v2,0);add(v2,i,0);
                    for(rt j=0;j<e[i].size();j++)if(j&1)e[v1].push_back(e[i][j]);
                    else e[v2].push_back(e[i][j]);
                }
            }
            
        }
        int mins(int x,int y){return dep[x]<dep[y]?x:y; }
        void LCA_init(){
            for(rt i=1;i<=t;i++)st[0][i]=q[i];
            for(rt i=1;i<=18;i++)
            for(rt j=1;j<=t;j++)
            st[i][j]=mins(st[i-1][j],st[i-1][min(t,j+(1<<i-1))]);
            for(rt i=2;i<=t;i++)lg2[i]=lg2[i>>1]+1;
        }
        inline int LCA(const int x,const int y){
            int L=fir[x],R=fir[y];if(L>R)swap(L,R);
            const int len=lg2[R-L+1];
            return mins(st[len][L],st[len][R-(1<<len)+1]);
        }
        inline ll dis(const int x,const int y){
            return deep[x]+deep[y]-deep[LCA(x,y)]*2;
        }
        inline bool anc(const int x,const int y){//x是否为y祖先 
            return dfn[x]<=dfn[y]&&dfn[x]+size[x]-1>=dfn[y];
        }
    }T1,T2,T3,xs;    
    void build(int n,int *A){
        xs.clear();//对于点集A在xs上建虚树 
        static int q[M],sta[M];int tott=n,topp=1;
        static bool vis[M];
        for(rt i=1;i<=n;i++)q[i]=A[i],vis[q[i]]=1;
        for(rt i=1;i<=n;i++)sorttable[i]=T2.dfn[q[i]];
        sort(q+1,q+n+1,cmp);
        for(rt i=n;i>=2;i--){
            int lca=T2.LCA(q[i],q[i-1]);
            if(!vis[lca])vis[lca]=1,q[++tott]=lca,col[lca]=0;
        }
        for(rt i=1;i<=tott;i++)sorttable[q[i]]=T2.dfn[q[i]];
        sort(q+1,q+tott+1,cmp);
        sta[topp=1]=q[1];
        for(rt i=2;i<=tott;i++){
            while(topp&&!T2.anc(sta[topp],q[i]))topp--;
            if(topp){
                ll val=-T2.deep[sta[topp]]+T2.deep[q[i]];
                xs.add(sta[topp],q[i],val);
            }sta[++topp]=q[i];
        }
        for(rt i=1;i<=tott;i++)vis[q[i]]=0;
        Root=q[1];
    }
    
    void printblack(int x,int pre,ll ds=0){//黑1白2
        if(x<=la)A[++sum]=x,col[x]=1,dist[x]=ds; 
        for(rt i=T1.F[x];i;i=T1.N[i])if(T1.a[i]!=pre&&!vis[i>>1])printblack(T1.a[i],x,ds+T1.c[i]);
    }
    void printwhite(int x,int pre,ll ds=0){//黑1白2
        if(x<=la)A[++sum]=x,col[x]=2,dist[x]=ds; 
        for(rt i=T1.F[x];i;i=T1.N[i])if(T1.a[i]!=pre&&!vis[i>>1])printwhite(T1.a[i],x,ds+T1.c[i]);
    }
    void get(int x,int pre){
        sz[x]=1;
        for(rt i=T1.F[x];i;i=T1.N[i])if(T1.a[i]!=pre&&!vis[i>>1]){
            get(T1.a[i],x);
            const int val=abs(all-2*sz[T1.a[i]]);
            if(val<nowmin)nowmin=val,ed=i;
            sz[x]+=sz[T1.a[i]];
        }
    }
    ll calc(int x,int y){//左黑右白 
        if(x==-1||y==-1)return -100000000000000ll;
        return dist[x]+dist[y]+T2.deep[x]+T2.deep[y]+T3.dis(x,y);
    }
    struct white{int x,y;};
    struct black{int x,y;};
    ll calcw(white x){
        return dist[x.x]+dist[x.y]+T2.deep[x.x]+T2.deep[x.y]+T3.dis(x.x,x.y);
    }
    ll calcb(black x){
        return dist[x.x]+dist[x.y]+T2.deep[x.x]+T2.deep[x.y]+T3.dis(x.x,x.y);
    }
    white maxw(white x,white y){
        if(x.x==-1&&x.y==-1)return y;
        if(y.x==-1&&y.y==-1)return x;
        if(x.x==-1||x.y==-1)return y;
        if(y.x==-1||y.y==-1)return x;
        if(calcw(x)>calcw(y))return x;else return y;
    }
    black maxb(black x,black y){
        if(x.x==-1&&x.y==-1)return y;
        if(y.x==-1&&y.y==-1)return x;
        if(x.x==-1||x.y==-1)return y;
        if(y.x==-1||y.y==-1)return x;
        if(calcb(x)>calcb(y))return x;else return y;
    }
    inline white operator +(const white x,const white y){
        return maxw(maxw(x,y),maxw(maxw(maxw((white){x.x,y.x},(white){x.x,y.y}),(white){x.y,y.x}),(white){x.y,y.y}));
    }
    inline black operator +(const black x,const black y){
        return maxb(maxb(x,y),maxb(maxb(maxb((black){x.x,y.x},(black){x.x,y.y}),(black){x.y,y.x}),(black){x.y,y.y}));
    }
    inline ll Calc(const black x,const white y){
        return max(max(max(calc(x.x,y.x),calc(x.x,y.y)),calc(x.y,y.x)),calc(x.y,y.y));
    }
    pair<black,white>DP(int x,ll val){
        pair<black,white>ret={{-1,-1},{-1,-1}}; 
        if(col[x]==1)ret.first.x=x;
        if(col[x]==2)ret.second.x=x;
        for(rt i=xs.F[x];i;i=xs.N[i]){
            pair<black,white>la=DP(xs.a[i],val);
            ll res=max(Calc(ret.first,la.second),Calc(la.first,ret.second))+val-2ll*T2.deep[x];
            ans=max(ans,res);
            ret.first=ret.first+la.first;
            ret.second=ret.second+la.second;
        }
        return ret;
    }
    void solve(int x,int siz){
        if(siz==1)return;
        nowmin=all=siz;
        get(x,x);
        int xx=T1.a[ed],yy=T1.a[ed^1];vis[ed>>1]=1;int now=sz[xx];
        sum=0;printblack(xx,yy);printwhite(yy,xx);B=xx;W=yy;
        build(sum,A);DP(Root,T1.c[ed]);
        solve(xx,now);solve(yy,siz-now);
    }
    int main(){
        n=read();la=n;
        for(rt i=1;i<n;i++){
            x=read();y=read();ll z=read();
            T1.add(x,y,z);
            T1.add(y,x,z);
        }
        for(rt i=1;i<n;i++){
            x=read();y=read();ll z=read();
            T2.add(x,y,z);
            T2.add(y,x,z);
        }
        for(rt i=1;i<n;i++){
            x=read();y=read();ll z=read();
            T3.add(x,y,z);
            T3.add(y,x,z);
        }
        T1.rebuild_init(1,1);T1.rebuild();
        T1.dfs(1,1);T1.LCA_init();T2.dfs(1,1);T2.LCA_init();T3.dfs(1,1);T3.LCA_init();
        solve(1,n);
        cout<<ans;
        return 0;
    }

     

  • 相关阅读:
    ASP.NET Web API 框架研究 Self Host模式下的消息处理管道
    ASP.NET Web API 框架研究 Web Host模式下的消息处理管道
    ASP.NET Web API 框架研究 核心的消息处理管道
    ASP.NET Web API 框架研究 Web Host模式路由及将请求转出到消息处理管道
    ASP.NET Web API 框架研究 ASP.NET Web API 路由
    ASP.NET Web API 框架研究 ASP.NET 路由
    ASP.NET Web API 入门 (API接口、寄宿方式、HttpClient调用)
    MVVM模式
    RESTful Web API 理解
    C# 函数式编程及Monads.net库
  • 原文地址:https://www.cnblogs.com/DreamlessDreams/p/10208849.html
Copyright © 2011-2022 走看看