zoukankan      html  css  js  c++  java
  • [APIO2018] Duathlon 铁人两项

    不经过重点,考虑点双

    点双,考虑圆方树

    两个点s,t,中间路径上,所有点双里的点都可以经过,特别地,s,t作为割点的时候,不能往后走,也就是不能经过身后的方点

    也就是,(s,t)经过树上路径上的所有圆点和方点

    把方点权值设为点双大小-2,圆点权值设为1,(s,t)路径上的权值就是c的选择方案数(不算s,t自己权值)

    问题转化为:求树上任意点对的距离和,(x,y),(y,x)算两次

    在转化为考虑每个点的贡献,树形DP即可

    注意:

    1.可能不连通

    2.sz统计的是圆点的个数

    3.最后乘2

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=200000+5;
    const int M=200000+5;
    int n,m;
    struct node{
        int nxt,to;
    }e[2*M];
    int hd[N],cnt;
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    int dfn[N],df;
    int low[N];
    ll ans=0;
    int vis[N];
    int val[N];
    int typ[N];
    vector<int>mem[N];
    int num;
    int sta[N],top;
    void tarjan(int x){
        typ[x]=1;
        val[x]=1;
        low[x]=dfn[x]=++df;
        sta[++top]=x;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(!dfn[y]){
                tarjan(y);
                low[x]=min(low[x],low[y]);
                if(low[y]>=dfn[x]){
                    ++num;
                    int z;
                    do{
                        z=sta[top];
                        mem[num].push_back(z);
                        --top;
                    }while(z!=y);
                    mem[num].push_back(x);
                }
            }else low[x]=min(low[x],dfn[y]);
        }
    }
    int sz[2*N];
    int totsz=0;
    void fin(int x,int fa){
        vis[x]=1;
        totsz+=typ[x];
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa) continue;
            fin(y,x);
        }
    }
    void dfs(int x,int fa){
        vis[x]=1;
        sz[x]=typ[x];
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa) continue;
            dfs(y,x);
            sz[x]+=sz[y];
        }
        ll tmp=totsz-sz[x];
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;;
            if(y==fa) continue;
            ans=ans+tmp*sz[y]*val[x];
            tmp+=sz[y];
        }
    }
    int main(){
        rd(n);rd(m);
        int x,y;
        for(reg i=1;i<=m;++i){
            rd(x);rd(y);
            add(x,y);add(y,x);
        }
        for(reg i=1;i<=n;++i){
            if(!dfn[i]) tarjan(i);
        }
        int tot=n;
        memset(hd,0,sizeof hd);
        cnt=0;
        //cout<<" num "<<num<<endl;
        for(reg i=1;i<=num;++i){
            ++tot;
            typ[tot]=0;
            val[tot]=mem[i].size()-2;
            //cout<<" tot "<<tot<<endl;
            for(reg j=0;j<(int)mem[i].size();++j){
                //cout<<" mem "<<mem[i][j]<<endl;
                add(tot,mem[i][j]);
                add(mem[i][j],tot);    
            }
        }
        for(reg i=1;i<=tot;++i){
            if(!vis[i]){
                totsz=0;
                fin(i,0);
                dfs(i,0);
            }
        }
        printf("%lld",ans*2);
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/2/15 9:04:01
    */
  • 相关阅读:
    剑指Offer
    剑指Offer
    剑指Offer
    选书
    马的遍历
    从事效应
    魔性的素数环1~20 自带解释~
    [POJ1236]Network of Schools(并查集+floyd,伪强连通分量)
    [HDOJ3974]Assign the task(建树胡搞)
    [HDOJ4027]Can you answer these queries?(线段树,特殊成段更新,成段查询)
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10382173.html
Copyright © 2011-2022 走看看