zoukankan      html  css  js  c++  java
  • BZOJ 5341: [Ctsc2018]暴力写挂 边分治+虚树

    和【洛谷5115】挺像的.  

    都是统计信息的时候是包含两个树的,那就在一个树上边分治,另一个树上跑一个虚树dp就好了.  

    式子这么拆:  

    $dep[i]+dep[j]-(dep[LCA(i,j)]+dep'[LCA'(i,j)]$

    $Rightarrow dep[i]+dep[j]-frac{1}{2}(dep[i]+dep[j]-dis(i,j)]-dep'[LCA'(i,j)])$

    $Rightarrow frac{1}{2}(dep[i]+dep[j]+dis(i,j)-2dep'[LCA'(i,j)])$

    其中 $dis(i,j)$ 可以拆成 $dis(i,u)+dis(j,v)+val(u,v)$,然后这个就用边分治来跑,把关键点扔到虚树上就行了 .

     code:

    #include <cstdio>  
    #include <string>
    #include <algorithm> 
    #include <cstring> 
    #include <vector>  
    
    #define N 1000002   
    #define ll long long 
    #define inf 0x3f3f3f3f 
    
    using namespace std;  
    
    int n;     
    ll ans=-inf,W;     
    
    namespace IO {  
    
        void setIO(string s) 
        {
            string in=s+".in"; 
            string out=s+".out"; 
            freopen(in.c_str(),"r",stdin);  
        }  
    
    };  
    
    namespace tree2 {     
    
        vector<int>G[N],clr;  
        ll dis[N]; 
        int edges,t,sta,tot;    
        int hd[N],to[N<<1],nex[N<<1],dep[N];    
        ll val[N<<1]; 
        int size[N],son[N],top[N],fa[N],dfn[N],re[N];  
        int S[N],col[N]; 
        ll value[N],max1[N],max2[N];           
    
        void add(int u,ll v,int c) 
        { 
            nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;  
        }  
    
        bool cmp(int a,int b)
        { 
            return dfn[a]<dfn[b];   
        } 
    
        void add_vir(int u,int v) 
        { 
            G[u].push_back(v);  
        } 
    
        void dfs1(int u,int ff) 
        { 
            fa[u]=ff,size[u]=1,dfn[u]=++t;  
            for(int i=hd[u];i;i=nex[i])
            { 
                int v=to[i]; 
                if(v==ff) continue;   
                dep[v]=dep[u]+1; 
                dis[v]=dis[u]+val[i];   
                dfs1(v,u); 
                size[u]+=size[v];   
                if(size[v]>size[son[u]]) son[u]=v; 
            }     
        } 
    
        void dfs2(int u,int tp) 
        {
            top[u]=tp; 
            if(son[u]) dfs2(son[u],tp); 
            for(int i=hd[u];i;i=nex[i]) 
                if(to[i]!=fa[u]&&to[i]!=son[u]) dfs2(to[i],to[i]); 
        }
    
        int LCA(int x,int y) 
        {
            while(top[x]!=top[y]) 
            {
                dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];  
            }
            return dep[x]<dep[y]?x:y;  
        } 
    
        void newnode(int x,ll v,int c) 
        {  
            re[++tot]=x;  
            col[x]=c;    
            value[x]=v;   
        } 
    
        void Insert(int x) 
        {   
            if(sta<=1) 
            {
                S[++sta]=x;   
                return;   
            }            
            int lca=LCA(x,S[sta]);     
            if(S[sta]==lca)  S[++sta]=x;   
            else 
            {
                while(sta>1&&dep[S[sta-1]]>=dep[lca]) add_vir(S[sta-1],S[sta]),--sta;   
                if(S[sta]==lca)  S[++sta]=x;  
                else 
                {
                    add_vir(lca,S[sta]);  
                    S[sta]=lca;   
                    S[++sta]=x;  
                }
            }
        }  
    
        void DP(int x) 
        {             
            clr.push_back(x);  
            max1[x]=max2[x]=-100000000000000000;    
            for(int i=0;i<G[x].size();++i) 
            {
                int y=G[x][i];  
                DP(y);     
                ans=max(ans,max1[x]+max2[y]+W-dis[x]*2);   
                ans=max(ans,max2[x]+max1[y]+W-dis[x]*2);         
                max1[x]=max(max1[x],max1[y]);   
                max2[x]=max(max2[x],max2[y]);   
            }    
            if(col[x]==1)  ans=max(ans,value[x]+max2[x]+W-dis[x]*2),max1[x]=max(max1[x],value[x]); 
            if(col[x]==2)  ans=max(ans,value[x]+max1[x]+W-dis[x]*2),max2[x]=max(max2[x],value[x]);    
        }  
    
        void solve() 
        { 
            sort(re+1,re+1+tot,cmp);   
            if(re[1]!=1) S[++sta]=1;         
            for(int i=1;i<=tot;++i)  Insert(re[i]);   
            while(sta>1)  add_vir(S[sta-1],S[sta]),--sta;    
            DP(1);       
            for(int i=0;i<clr.size();++i) 
            {
                int x=clr[i];   
                max1[x]=max2[x]=value[x]=col[x]=0;           
                G[x].clear();   
            }                      
            clr.clear();      
            tot=sta=0;              
        }  
    
        void Initialize() 
        {     
            dfs1(1,0); 
            dfs2(1,1);   
        }    
    
    };  
    
    namespace tree1 {  
    
        int tot,totsize,rt1,rt2,ed,mx;  
        int edges1=1,edges2=1;   
        int hd[N],pre[N<<1],vis[N<<2],size[N<<1]; 
        ll dis[N<<1];  
    
        struct Edge { 
            int to; 
            ll w; 
            int nex;  
        }e[N<<2],edge[N<<2];    
    
        void add(int u,ll v,int c) 
        {
            e[++edges1].nex=pre[u],pre[u]=edges1,e[edges1].to=v,e[edges1].w=c;   
        }
    
        void add_div(int u,ll v,int c) 
        {    
            edge[++edges2].nex=hd[u],hd[u]=edges2,edge[edges2].to=v,edge[edges2].w=c;  
        } 
    
        void getdis(int u,int ff) 
        {   
            for(int i=pre[u];i;i=e[i].nex) 
            { 
                int v=e[i].to; 
                if(v==ff) continue;   
                dis[v]=dis[u]+e[i].w;   
                getdis(v,u);  
            }
        }  
    
        void Build_Tree(int u,int fa) 
        {  
            int ff=0; 
            for(int i=pre[u];i;i=e[i].nex) 
            {   
                int v=e[i].to;  
                if(v==fa) continue;    
                if(!ff) 
                {   
                    ff=u;   
                    add_div(u,v,e[i].w);  
                    add_div(v,u,e[i].w);  
                }
                else
                {
                    ++tot;     
                    add_div(ff,tot,0);  
                    add_div(tot,ff,0); 
                    add_div(tot,v,e[i].w);   
                    add_div(v,tot,e[i].w);         
                    ff=tot;  
                }
                Build_Tree(v,u);  
            }
        }      
    
        void find_edge(int x,int fa) 
        {  
            size[x]=1;    
            for(int i=hd[x];i;i=edge[i].nex) 
            {
                int y=edge[i].to;   
                if(y==fa||vis[i])  continue;   
                find_edge(y,x);   
                int now=max(size[y],totsize-size[y]);           
                if(now<mx) 
                {
                    mx=now;    
                    rt1=y;   
                    rt2=x;                
                    ed=i;  
                }
                size[x]+=size[y]; 
            }
        }  
    
        void dfs(int u,int ff,ll d,int ty) 
        {        
            if(u<=n) 
            {
                tree2::newnode(u,dis[u]+d,ty);     
            }
            for(int i=hd[u];i;i=edge[i].nex) 
            {
                int v=edge[i].to;   
                if(v==ff||vis[i]) continue;    
                dfs(v,u,d+edge[i].w,ty); 
            }
        } 
    
        void Divide_And_conquer(int x) 
        {     
            if(totsize==1) return;  
            rt1=rt2=ed=0,mx=inf;   
            find_edge(x,0);          
            vis[ed]=vis[ed^1]=1;            
            W=edge[ed].w;       
            dfs(rt1,0,0,1);  
            dfs(rt2,0,0,2);  
            tree2::solve();          
            int sizert1=size[rt1],sizert2=totsize-size[rt1];  
            int tmprt1=rt1,tmprt2=rt2;    
            totsize=sizert1;    
            Divide_And_conquer(tmprt1);   
            totsize=sizert2;  
            Divide_And_conquer(tmprt2);   
        }
    }; 
    
    int main() 
    { 
        // IO::setIO("input"); 
        int i,j;    
        scanf("%d",&n);      
        for(i=1;i<n;++i) 
        {
            int x,y,z; 
            scanf("%d%d%d",&x,&y,&z);  
            tree1::add(x,y,(ll)z);   
            tree1::add(y,x,(ll)z); 
        }
        for(i=1;i<n;++i) 
        {
            int x,y,z; 
            scanf("%d%d%d",&x,&y,&z);          
            tree2::add(x,y,(ll)z); 
            tree2::add(y,x,(ll)z);  
        } 
        tree2::Initialize();   
        tree1::tot=n;    
        tree1::getdis(1,0);   
        tree1::Build_Tree(1,0);               
        tree1::totsize=tree1::tot;   
        tree1::Divide_And_conquer(1);    
        ans>>=1;    
        for(i=1;i<=n;++i)  ans=max(ans,tree1::dis[i]-tree2::dis[i]);    
        printf("%lld
    ",ans); 
        return 0;   
    }
    

      

  • 相关阅读:
    高斯消元
    丑数
    扩展欧几里得算法与线性同余方程
    数论-求逆元
    数论-快速幂-快速乘
    宋逸轩长难句 2
    宋逸轩长难句 1
    c语言 文件
    c语言程序结构
    c语言结构类型
  • 原文地址:https://www.cnblogs.com/guangheli/p/12111583.html
Copyright © 2011-2022 走看看