zoukankan      html  css  js  c++  java
  • [HDU5739]Fantasia(圆方树DP)

    题意:给一张无向点带有权无向图。定义连通图的权值为图中各点权的乘积,图的权值为其包含的各连通图的权和。设z_i为删除i点后图的权值,求$S = (sumlimits_{i=1}^{n}icdot z_i) ext{ mod } (10^9 + 7)$。

    显然和点双有关。回忆各种tarjan:缩SCC得DAG,缩边BCC得一棵树,我们要想办法把点BCC也缩成一棵树。

    tarjan求点双,然后给每个点双新建一个点,将这个BCC内的所有点连向这个点。

    因为点与点之间没有边,SCC与SCC之间没有边,所以可以证明这是一棵树。这个算法有个名字叫Block Forest Data Structure.

    缩成树之后随便选一个SCC点作为根,显然所有非叶子点都是割点(SCC虚拟点除外),叶子则都是非割点。

    在这棵树上直接DP即可,为了方便计算直接将SCC点权赋为1。

    接着是一些注意点:

      1. 孤立点要特殊处理,因为一个点不是点双。

      2. 缩点后的点的个数可能达到$2n$。

      3. 当前点为割点的判定:low[k]>=dfn[x]而不是low[x]==dfn[x],且这里要保证在此之前k未被访问过,具体看代码。

      4. tarjan弹栈的时候要注意,弹到k为止,x特殊处理。因为x和k在栈中可能不是连续的。

    UPD:才知道这个就是圆方树。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define mem(a) memset(a,0,sizeof(a))
     5 #define rep(i,l,r) for (int i=(l),_=(r); i<=_; i++)
     6 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     7 using namespace std;
     8 
     9 const int N=3000010,mod=1000000007;
    10 int T,n,m,tot,top,u,v,S,tim,bcc,d[N];
    11 int w[N],p[N],val[N],ans[N],stk[N],low[N],dfn[N],bel[N];
    12 bool vis[N];
    13 inline void up(int &x,int y){ x+=y; if (x>=mod) x-=mod; }
    14 
    15 int ksm(int a,int b){
    16     int res=1;
    17     for (; b; a=1ll*a*a%mod,b>>=1)
    18         if (b&1) res=1ll*res*a%mod;
    19     return res;
    20 }
    21 
    22 struct E{
    23     int cnt,h[N],to[N<<1],nxt[N<<1];
    24     void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    25     
    26     void dfs(int x,int fa){
    27         vis[x]=1; val[x]=w[x]; bel[x]=tot;
    28         For(i,x) if ((k=to[i])!=fa)
    29             dfs(k,x),val[x]=1ll*val[x]*val[k]%mod;
    30     }
    31     
    32     void DP(int x,int fa){
    33         vis[x]=1; ans[x]=(S-p[bel[x]]+mod)%mod;
    34         For(i,x) if ((k=to[i])!=fa) DP(k,x),up(ans[x],val[k]);
    35         up(ans[x],1ll*p[bel[x]]*ksm(val[x],mod-2)%mod);
    36     }
    37 }G,G1;
    38 
    39 void tarjan(int x,int fa){
    40     dfn[x]=low[x]=++tim; stk[++top]=x;
    41     for (int i=G.h[x],k; i; i=G.nxt[i]) if ((k=G.to[i])!=fa){
    42         if (dfn[k]) low[x]=min(low[x],dfn[k]);
    43         else{
    44             tarjan(k,x),low[x]=min(low[x],low[k]);
    45             if (low[k]>=dfn[x]){
    46                 bcc++; w[n+bcc]=1; int t;
    47                 while (1){
    48                     t=stk[top]; //printf("%d %d
    ",t,n+bcc);
    49                     G1.add(t,n+bcc); G1.add(n+bcc,t);
    50                     top--; if (t==k) break;
    51                 }
    52                 G1.add(x,n+bcc); G1.add(n+bcc,x);
    53             }
    54         }
    55     }
    56 }
    57 
    58 void init(){ rep(i,0,n+bcc) G.h[i]=G1.h[i]=dfn[i]=d[i]=vis[i]=0; G.cnt=G1.cnt=tot=top=tim=bcc=S=0; }
    59 
    60 int main(){
    61     freopen("hdu5739.in","r",stdin);
    62     freopen("hdu5739.out","w",stdout);
    63     for (scanf("%d",&T); T--; init()){
    64         scanf("%d%d",&n,&m);
    65         rep(i,1,n) scanf("%d",&w[i]);
    66         rep(i,1,m) scanf("%d%d",&u,&v),G.add(u,v),G.add(v,u),d[u]++,d[v]++;
    67         rep(i,1,n) if (!dfn[i]) tarjan(i,0);
    68         rep(i,n+1,n+bcc) if (!vis[i]) tot++,G1.dfs(i,0),p[tot]=val[i],up(S,p[tot]);
    69         rep(i,1,n) if (!d[i]) up(S,w[i]);
    70         rep(i,1,n) if (!d[i]) ans[i]=(S-w[i]+mod)%mod;
    71         //rep(i,1,n+bcc) printf("%d ",val[i]); puts("");
    72         rep(i,0,n+bcc) vis[i]=0;
    73         rep(i,n+1,n+bcc) if (!vis[i]) G1.DP(i,0);
    74         //rep(i,1,n) printf("%d ",ans[i]); puts("");
    75         int res=0;
    76         rep(i,1,n) up(res,1ll*i*ans[i]%mod);
    77         printf("%d
    ",res);
    78     }
    79     return 0;
    80 }

     

  • 相关阅读:
    Shiro认证过程?
    使用过Redis做异步队列么,你是怎么用的?
    使用 Spring Boot有什么好处
    Spring Boot、Spring MVC 和 Spring 有什么区别?
    es
    python并发编程
    Go基础05
    Go04基础
    Go03基础
    Go基础02
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9110226.html
Copyright © 2011-2022 走看看