• LOJ #2587. 「APIO2018」铁人两项 (圆方树,树形DP)


    开始的时候没有借助圆方树去思考,思路非常混乱,想了很长时间后冷静下来发现这题不就是分类讨论简单题嘛...

    题目不难,分两种情况讨论:

    设当前点为中间点(圆点) 

    • 起点从一个儿子的子树进入到中间点后进入到另一个儿子的子树. 
    • 起点从一个儿子的子树进入到中间点后仍然回到该儿子子树中(相当于上一条的子问题)    
    • 然后对于儿子(方点)直接累加,父亲(方点)要扣掉当前子树的影响.  

    code: 

    #include <cstdio>
    #include <cstring>
    #include <algorithm>  
    #include <vector>    
    #define N 200006   
    #define ll long long 
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;      
    vector<int>G[N]; 
    ll ans;   
    int edges,tim,tot,n,m,fr,SIZE;  
    int hd[N<<1],to[N<<1],nex[N<<1],dfn[N],low[N],S[N],deg[N],size[N]; 
    ll g[N],F[N];     
    void add(int u,int v)
    {
        nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; 
    }
    void tarjan(int x)
    {
        dfn[x]=low[x]=++tim;     
        S[++fr]=x;   
        ++SIZE; 
        for(int i=hd[x];i;i=nex[i])
        {
            int y=to[i];    
            if(!dfn[y])
            {
                tarjan(y);  
                low[x]=min(low[x],low[y]);   
                if(low[y]>=dfn[x])
                {
                    ++tot;        
                    G[x].push_back(tot);
                    G[tot].push_back(x);  
                    ++deg[tot];     
                    for(int p=0;p!=y;--fr)
                    {
                        p=S[fr];       
                        ++deg[tot];     
                        G[tot].push_back(p);
                        G[p].push_back(tot);     
                    }                
                }
            }  
            else 
            {
                low[x]=min(low[x],dfn[y]);              
            }
        }   
    }    
    void dfs(int x,int ff) 
    {
        size[x]=(x<=n);     
        for(int i=0;i<G[x].size();++i) 
        {
            int y=G[x][i];   
            if(y==ff) continue;    
            dfs(y,x);   
            size[x]+=size[y];   
        }
    }    
    void solve(int x,int ff) 
    {    
        if(x<=n) 
        {
            int cu=0; 
            for(int i=0;i<G[x].size();++i) 
            {
                int y=G[x][i];   
                if(y==ff)  cu=SIZE-size[x];     
                else cu=size[y];    
                ans+=1ll*cu*(SIZE-cu-1);       
            }
            if(ff) 
            { 
                ans+=g[ff]-1ll*size[x]*SIZE;      
                ans-=1ll*size[x]*(SIZE-2*size[x]);   
            }
        }            
        else
        { 
            for(int i=0;i<G[x].size();++i) 
            {
                int y=G[x][i]; 
                if(y==ff) continue;      
                F[x]+=1ll*size[y]*(size[x]-size[y]);     
                g[x]+=1ll*size[y]*(SIZE-size[y]);      
            }
            g[x]+=1ll*size[x]*(SIZE-size[x]);                  
            ans+=1ll*F[x];         
        }
        for(int i=0;i<G[x].size();++i) 
            if(G[x][i]!=ff) solve(G[x][i],x); 
    }
    int main() 
    { 
        // setIO("input");            
        scanf("%d%d",&n,&m);  
        tot=n;    
        for(int i=1;i<=m;++i) 
        {
            int x,y; 
            scanf("%d%d",&x,&y);   
            add(x,y),add(y,x);  
        }
        for(int i=1;i<=n;++i) 
        {
            if(!dfn[i]) 
            {
                tim=SIZE=fr=0; 
                tarjan(i);    
                dfs(i,0);
                solve(i,0);    
            }
        }
        printf("%lld
    ",ans);   
        return 0; 
    }
    

      

  • 相关阅读:
    Angularjs 设置全局变量的3种方法
    prevent to do sth 与 prevent sb (from) doing 用法
    软件测试技术对程序员的重要性
    Javascript中setTimeout()以及clearTimeout( )的使用
    Javascript异步编程的常用方法
    软件设计原则总结
    为sublime Text3 安装插件JS Format
    javascript中 if(变量)和if(变量==true)的区别
    Ping 命令
    ipconfig
  • 原文地址:https://www.cnblogs.com/guangheli/p/12590553.html
Copyright © 2020-2023  润新知