HDU 5739(点双连通)

来源:互联网 发布:淘宝联盟互刷 编辑:程序博客网 时间:2024/03/29 04:08

题目大意:给定一个无向图,对于每个连通分量的权值为其中点的权值乘积,而整个无向图的权值为所以连通分量的权值和。Gi表示删除点i,图的权值,求sum(i*Gi)%(10e+7)


显然只有删除割点才会改变图的连通性,但我也没有想到怎么解决,这里根据官方题解

显然, 只要删掉关键点才会使图不联通. 对于其他点, 权值很容易计算.

首先求出所有的点双联通分量, 对于每一个点双联通分量SSS, 新建一个节点sss, 向SSS中每个节点vvv连边. 这样一来, 新增的点和原来图中的点会构成一个森林(据说这个有个名字, block forest data structure). 很容易观察到, 叶子节点肯定都是非关键点, 内部节点要么是关键点, 要么是新增的节点.

对于这个森林FFF, 删掉一个关键点或者一个叶子iii之后, 会得到一个新森林FiF_iFi, 这个FiF_iFi对应的连通块集合和GiG_iGi对应的连通块集合其实是一样的(不考虑那些新增的点). 显然GiG_iGi的权值和FiF_iFi的权值也是一样的,FiF_iFi的权值我们很容易通过树形dp算出来, 那么GiG_iGi的权值也随之而出.

根据对应性质,先求出点双连通分量,再进行树形dp即可。开始求点双连通时用了vector超时,改了就没问题了。


#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <vector>#include <stack>#include <queue>#include <map>#include <ctime>using namespace std;#define ll long longconst int maxn=800005;const ll mod=1000000007;ll pri[maxn];int head[maxn];int to[maxn],ne[maxn],from[maxn];int cot;inline void addedge(int u,int v){    from[cot]=u;    to[cot]=v;    ne[cot]=head[u];    head[u]=cot++;}int head1[maxn];int to1[maxn];int ne1[maxn];int cot1;inline void addEdge(int u,int v){    to1[cot1]=v;    ne1[cot1]=head1[u];    head1[u]=cot1++;}ll pow_mod(ll a,ll b){    ll res=1;    while(b){        if(b&1)(res*=a)%=mod;        (a*=a)%=mod;        b>>=1;    }    return res;}int dfn[maxn];int dfs_cot;int bcc_cot;int st[maxn];int top;bool vis[maxn];int dfs(int u,int fa){    vis[u]=true;    int lowu=dfn[u]=++dfs_cot;    for(int i=head[u];~i;i=ne[i]){        int v=to[i];        if(!vis[v]){            st[top++]=i;            int lowv=dfs(v,u);            lowu=min(lowv,lowu);            if(lowv>=dfn[u]){                bcc_cot++;                //printf("bcc[%d]:\n",bcc_cot);                for(;;){                    if(top==0)break;                    int e=st[--top];                    //printf("e[%d]:%d %d\n",e,from[e],to[e]);                    //if(bcc_id[from[e]]!=bcc_cot)printf("push:%d\n",from[e]);                    addEdge(bcc_cot,from[e]);                    addEdge(from[e],bcc_cot);                    //if(bcc_id[to[e]]!=bcc_cot)printf("push:%d\n",to[e]);                    addEdge(bcc_cot,to[e]);                    addEdge(to[e],bcc_cot);                    pri[bcc_cot]=1;                    if(from[e]==u&&to[e]==v)break;                }            }        }        else if(dfn[v]<dfn[u]&&v!=fa){            st[top++]=i;            lowu=min(lowu,dfn[v]);        }    }    return lowu;}void init(int n){    bcc_cot=n;    top=0;    cot=0;    dfs_cot=0;    cot1=0;    memset(head1,-1,sizeof(head1));    memset(head,-1,sizeof(head));    memset(vis,0,sizeof(vis));}ll sum[maxn];ll product[maxn];void dp_dfs(int u,int fa){    vis[u]=true;    sum[u]=0;    product[u]=pri[u];    for(int i=head1[u];~i;i=ne1[i]){        int v=to1[i];        if(v==fa)continue;        if(!vis[v]){            dp_dfs(v,u);            sum[u]=(sum[u]+product[v])%mod;            product[u]=(product[v]*product[u])%mod;        }    }}void dp(int u,int fa){    dfn[u]=1;    if(fa!=0){        int tmp=product[fa]*pow_mod(product[u],mod-2)%mod;        sum[u]=(sum[u]+tmp)%mod;        product[u]=product[fa];    }    for(int i=head1[u];~i;i=ne1[i]){        int v=to1[i];        if(!dfn[v]){            dp(v,u);        }    }}int main(){    int t,n,m;    int u,v;    scanf("%d",&t);    while(t--){        scanf("%d %d",&n,&m);        init(n);        for(int i=1;i<=n;i++){            scanf("%lld",&pri[i]);            pri[i]%=mod;        }        cot=0;        for(int i=0;i<m;i++){            scanf("%d %d",&u,&v);            addedge(u,v);            addedge(v,u);        }        for(int i=1;i<=n;i++){            if(!vis[i])dfs(i,0);        }        memset(vis,0,sizeof(vis));        memset(dfn,0,sizeof(dfn));        ll ans=0;        for(int i=1;i<=n;i++){            if(!vis[i]){                dp_dfs(i,0);                dp(i,0);                (ans+=product[i])%=mod;            }        }/*        for(int i=1;i<=bcc_cot;i++){            printf("sum[%d]:%lld\n",i,sum[i]);            printf("pro[%d]:%lld\n",i,product[i]);        }        printf("ans:%lld\n",ans);*/        ll fans=0;        for(int i=1;i<=n;i++){            (fans+=(i*(ans+sum[i]-product[i]+mod))%mod)%=mod;        }        printf("%lld\n",fans);    }    return 0;}


0 0
原创粉丝点击