• [APIO2018]铁人两项(圆方树)


    过了14个月再重新看这题,发现圆方树从来就没有写过。然后写了这题发现自己APIO2018打铁的原因竟然是没开long long,将树的部分的O(n)写挂了(爆int),毕竟去年APIO时我啥都不会,连tarjan都写不来,活该打铁。

    不扯了写题解。

    首先建立圆方树,然后任意枚举圆点s和f,然后c可以在这两个点路径中每个点双的点挑选。所以令圆点值为-1,方点值为点双大小,然后选法是圆点路径权值和。然后计算每个点出现多少次,可以对每个连通块树形DP求解,然后这道题就没了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=2e5+7;
    vector<int>G1[N],G2[N];
    int n,m,tot,sum,tim,top,low[N],dfn[N],q[N],sz[N],val[N];
    ll ans;
    void tarjan(int u)
    {
        dfn[u]=low[u]=++tim,q[++top]=u;
        sz[u]=1,val[u]=-1;
        for(int i=0;i<G1[u].size();i++)
        if(!dfn[G1[u][i]])
        {
            int v=G1[u][i];
            tarjan(v),low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u])
            {
                G2[u].push_back(++tot),val[tot]=1;
                int x=0;
                do{
                    x=q[top--],G2[tot].push_back(x);
                    sz[tot]+=sz[x],val[tot]++;
                }while(x!=v);
                sz[u]+=sz[tot];
            }
        }
        else low[u]=min(low[u],dfn[G1[u][i]]);
    }
    void dfs(int u)
    {
        if(u<=n)ans+=1ll*(sum-1)*val[u];
        ans+=1ll*(sum-sz[u])*sz[u]*val[u];
        for(int i=0;i<G2[u].size();i++)
        ans+=1ll*(sum-sz[G2[u][i]])*sz[G2[u][i]]*val[u],dfs(G2[u][i]);
    }
    int main()
    {
        scanf("%d%d",&n,&m),tot=n;
        for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),G1[x].push_back(y),G1[y].push_back(x);
        for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i),sum=sz[i],dfs(i);
        printf("%lld",ans);
    }
    View Code
  • 相关阅读:
    使用树莓派3获取CPU温度
    使用树莓派控制继电器
    Darknet图像训练的步骤
    Faster-Rcnn图像识别训练的步骤
    Centos7中ELK集群安装流程
    近年来较流行的搜索引擎框架
    机器学习中,使用NMS对框取优
    当前Azure中国可使用的虚拟机的Size列表
    汉语词性对照表[北大标准/中科院标准]
    Linux中禁用THP(Transparent Huge Pages)
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/11154790.html
Copyright © 2020-2023  润新知