zoukankan      html  css  js  c++  java
  • 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; 
    }
    

      

  • 相关阅读:
    Windows server 2016 解决“无法完成域加入,原因是试图加入的域的SID与本计算机的SID相同。”
    Windows Server 2016 辅助域控制器搭建
    Windows Server 2016 主域控制器搭建
    Net Framework 4.7.2 覆盖 Net Framework 4.5 解决办法
    SQL SERVER 2012更改默认的端口号为1772
    Windows下彻底卸载删除SQL Serever2012
    在Windows Server2016中安装SQL Server2016
    SQL Server 创建索引
    C#控制台或应用程序中两个多个Main()方法的设置
    Icon cache rebuilding with Delphi(Delphi 清除Windows 图标缓存源代码)
  • 原文地址:https://www.cnblogs.com/guangheli/p/12590553.html
Copyright © 2011-2022 走看看