zoukankan      html  css  js  c++  java
  • 2015-2016 ACM-ICPC Northeastern European Regional Contest (NEERC 15)C

    题意:给一颗仙人掌,要求移动一条边,不能放在原处,移动之后还是一颗仙人掌的方案数(仙人掌:无向图,每条边只在一个环中),等价于先删除一条边,然后加一条边
    题解:对于一颗仙人掌,分成两种边,1:环边:环上的边2,树边:非环上的边
    考虑1.删除树边,那么只需联通两个联通快,那么方案数就是两个联通块乘积-1(除去删除的边)
    2.删除环边,那么我们假设删除所有环,那么图变成了深林,方案数就是深林中每棵树任意两点连接,方案数就是全部的和,先维护一个每个环上的点有多少树边,对于每个树边联通块(大小x)共贡献是x*(x-1)/2-(x-1),对于每个环,我们先算出所有答案,按个减去每个环上点的贡献,然后考虑删除环边之后总树边联通块的贡献
    bcc维护树边,并查集维护树边联通块

    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3)
    //#pragma GCC optimize(4)
    //#pragma GCC optimize("unroll-loops")
    //#pragma comment(linker, "/stack:200000000")
    //#pragma GCC optimize("Ofast,no-stack-protector")
    //#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define db double
    #define mp make_pair
    #define pb push_back
    #define pi acos(-1.0)
    #define ll long long
    #define vi vector<int>
    #define mod 1000000007
    #define ld long double
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    #define pll pair<ll,ll>
    #define pil pair<int,ll>
    #define pli pair<ll,int>
    #define pii pair<int,int>
    //#define cd complex<double>
    #define ull unsigned long long
    //#define base 1000000000000000000
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    #define fin freopen("a.txt","r",stdin)
    #define fout freopen("a.txt","w",stdout)
    #define fio ios::sync_with_stdio(false);cin.tie(0)
    inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    inline void sub(ll &a,ll b){a-=b;if(a<0)a+=mod;}
    inline void add(ll &a,ll b){a+=b;if(a>=mod)a-=mod;}
    template<typename T>inline T const& MAX(T const &a,T const &b){return a>b?a:b;}
    template<typename T>inline T const& MIN(T const &a,T const &b){return a<b?a:b;}
    inline ll qp(ll a,ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
    inline ll qp(ll a,ll b,ll c){ll ans=1;while(b){if(b&1)ans=ans*a%c;a=a*a%c,b>>=1;}return ans;}
    
    using namespace std;
    
    const double eps=1e-8;
    const ll INF=0x3f3f3f3f3f3f3f3f;
    const int N=100000+100,maxn=50000+10,inf=0x3f3f3f3f;
    
    int n,m;
    vi v[N];
    int dfn[N],low[N],ind,pre[N],fa[N];
    ll ans,sum,sz[N],tr[N];
    map<pii,bool>tree;
    int Find(int x){return fa[x]==x?x:fa[x]=Find(fa[x]);}
    void tarjan(int u,int f)
    {
        sz[u]=1;
        dfn[u]=low[u]=++ind;
        for(int x:v[u])
        {
            if(x==f)continue;
            if(!dfn[x])
            {
                tarjan(x,u);
                sz[u]+=sz[x];
                low[u]=min(low[u],low[x]);
                if(low[x]>dfn[u])tree[mp(u,x)]=tree[mp(x,u)]=1,ans+=sz[x]*(n-sz[x])-1;
            }
            else if(dfn[x]<dfn[u])low[u]=min(low[u],dfn[x]);
        }
    }
    void dfs(int u,int f)
    {
        dfn[u]=1;
        for(int x:v[u])
        {
            if(x==f)continue;
            if(!dfn[x]&&tree.find(mp(u,x))!=tree.end())//tree edge
            {
                dfs(x,u);
                int fx=Find(u),fy=Find(x);
                if(fx!=fy)fa[fx]=fy,tr[fy]+=tr[fx];
            }
        }
    }
    
    void dfs1(int u,int f)
    {
        dfn[u]=1;
        for(int x:v[u])
        {
            if(x==f)continue;
            if(!dfn[x])pre[x]=u,dfs1(x,u);
            else if(dfn[x]==1)
            {
                ll res=sum,co=0,p=0;
                for(int now=u;now!=x;now=pre[now])
                {
                    int fx=Find(now);
                    co+=tr[fx],p++,res-=1ll*(tr[fx]-1)*tr[fx]/2-(tr[fx]-1);
                }
                int fx=Find(x);
                co+=tr[fx],p++,res-=1ll*(tr[fx]-1)*tr[fx]/2-(tr[fx]-1);
                res=(res+1ll*(co-1)*co/2-(co-1)-1)*p;
    //            printf("%d %d %lld %lld %lld***
    ",u,x,co,p,res);
                ans+=res;
            }
        }
        dfn[u]=2;
    }
    int main()
    {
        freopen("cactus.in","r",stdin);
        freopen("cactus.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)fa[i]=i,tr[i]=1;
        for(int i=0;i<m;i++)
        {
            int x,k,last=0;scanf("%d",&k);
            while(k--)
            {
                scanf("%d",&x);
                if(last)v[last].pb(x),v[x].pb(last);
                last=x;
            }
        }
        tarjan(1,-1);
    //    printf("%lld
    ",ans);
        memset(dfn,0,sizeof dfn);
        for(int i=1;i<=n;i++)if(!dfn[i])dfs(i,-1);
        for(int i=1;i<=n;i++)
        {
            if(fa[i]==i)
            {
                sum+=1ll*(tr[i]-1)*tr[i]/2-(tr[i]-1);
    //            printf("%d %d
    ",i,tr[i]);
            }
        }
        memset(dfn,0,sizeof dfn);
        dfs1(1,-1);
        printf("%lld
    ",ans);
        return 0;
    }
    /********************
    9 4
    5 1 2 3 4 5
    4 2 8 7 4
    2 6 7
    2 8 9
    ********************/
    
  • 相关阅读:
    跨期套利策略
    读书笔记 量化交易:如何建立自己的算法交易事业
    ESP8266固件修改可以控制多个IO方法
    ESP8266固件烧录方法
    关于毕设WiFi选型
    关于(x&y)+((x^y)>>1)的探究
    QML添加右键菜单
    初学QML之QML和C++混合方法
    初学QML之qmlRegisterType
    我的第一个QML Button的实现
  • 原文地址:https://www.cnblogs.com/acjiumeng/p/9966168.html
Copyright © 2011-2022 走看看