zoukankan      html  css  js  c++  java
  • BZOJ 3924: [Zjoi2015]幻想乡战略游戏 动态点分治

    细节挺多的,但是也确实加深了我对动态点分治的理解. 

    这段代码值得关注: 

    ll query(int u) 
    {
        ll re=calc(u);        
        for(int i=hd[u];i;i=nex[i])
        {
        	ll t=calc(to[i]);
        	if(t<re) return query(hto[i]);    
        }
        return re;     
    }
    

     

    点分树的结构是和原树不同的. 

    我们知道,最优决策点和根节点的连线上的点的答案一定是越来越优的. 

    而如果发现 $to[i]$ 所在子树中,$to[i]$ 更优,那么想在点分树中到达 $to[i]$,直接走到 $to[i]$所在重心即可. 

    开始的时候思维太僵化了,一直想的是只靠重心之间转移,但其实我们也要将点分树和原树结合起来. 

    #include <cstdio> 
    #include <vector>    
    #include <algorithm>  
    #define N 100004
    #define inf 1000000000000000
    #define ll long long  
    #define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)
    using namespace std; 
    int edges,n;  
    int hd[N],to[N<<1],nex[N<<1],val[N<<1], hto[N<<1];   
    void add(int u,int v,int c)
    {
        nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c; 
    }
    namespace tree
    {    
        ll dis[N]; 
        int fa[N],top[N],size[N],son[N],dep[N];
        void dfs1(int u,int ff)
        { 
            fa[u]=ff,size[u]=1; 
            for(int i=hd[u];i;i=nex[i]) 
                if(to[i]!=ff) 
                {
                    int v=to[i];  
                    dep[v]=dep[u]+1,dis[v]=dis[u]+1ll*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; 
        }
        ll Dis(int x,int y)
        {
            return dis[x]+dis[y]-2ll*dis[LCA(x,y)];    
        }
    }; 
    vector<int>e[N];   
    int root,sn;
    int Fa[N],mx[N],size[N],vis[N];
    ll F[N],G[N],num[N],tmp;   
    void getroot(int u,int ff)
    {
        size[u]=1,mx[u]=0;  
        for(int i=hd[u];i;i=nex[i]) 
            if(to[i]!=ff&&!vis[to[i]]) 
                getroot(to[i],u),size[u]+=size[to[i]],mx[u]=max(mx[u],size[to[i]]);
        mx[u]=max(mx[u],sn-size[u]); 
        if(mx[u]<mx[root]) root=u;
    } 
    void dfs(int u,int ff)
    {
        size[u]=1; 
        for(int i=hd[u];i;i=nex[i]) 
            if(to[i]!=ff&&!vis[to[i]]) 
                dfs(to[i],u),size[u]+=size[to[i]]; 
    }
    void prepare(int u)
    {
        vis[u]=1; 
        for(int i=hd[u];i;i=nex[i]) 
            if(!vis[to[i]]) 
            {
                dfs(to[i],u),root=0,sn=size[to[i]],getroot(to[i],u),hto[i]=root,Fa[root]=u,prepare(root);        
            }
    }
    void Update(int u,ll v)
    { 
        int U=u; 
        num[u]+=v; 
        for(;Fa[u];u=Fa[u]) 
        {
            F[Fa[u]]+=v*tree::Dis(U,Fa[u]);        
            G[u]+=v*tree::Dis(U,Fa[u]);      
            num[Fa[u]]+=v; 
        }
    }      
    ll calc(int u) 
    {
        ll re=F[u];     
        int U=u; 
        for(;Fa[u];u=Fa[u])
        { 
            re+=F[Fa[u]]-G[u]+1ll*(num[Fa[u]]-num[u])*tree::Dis(U,Fa[u]);      
        } 
        return re;     
    }
    ll query(int u) 
    {
        ll re=calc(u);        
        for(int i=hd[u];i;i=nex[i])
        {
        	ll t=calc(to[i]);
        	if(t<re) return query(hto[i]);    
        }
        return re;     
    }
    int main()  
    {
        int i,j,Q; 
        //  setIO("input");   
        scanf("%d%d",&n,&Q); 
        for(i=1;i<n;++i) 
        {
            int a,b,c; 
            scanf("%d%d%d",&a,&b,&c),add(a,b,c),add(b,a,c); 
        } 
        int cc=0; 
        tree::dfs1(1,0); 
        tree::dfs2(1,1);   
        sn=n,mx[0]=n,root=0,getroot(1,0),cc=root,prepare(root); 
        for(int cas=1;cas<=Q;++cas)
        {
            int u,e; 
            scanf("%d%d",&u,&e), Update(u,1ll*e);  
            printf("%lld
    ",query(cc));     
        }
        return 0; 
    }
    

      

  • 相关阅读:
    (剑指offer)斐波那契数列
    手写Vue源码 watch的实现
    Vue源码之异步批量任务更新
    手写Vue源码之 依赖收集
    C# 测试代码#if DEBUG使用
    shell脚本编程相关7
    C#中关于ref和out的认识
    shell脚本编程相关6
    shell脚本编程相关5
    shell脚本编程相关4
  • 原文地址:https://www.cnblogs.com/guangheli/p/11451515.html
Copyright © 2011-2022 走看看