HDU 5739 (点双连通 树DP)

来源:互联网 发布:淘宝宝贝流量突然下降 编辑:程序博客网 时间:2024/05/17 00:11

题目链接:点击这里

题意:定义连通分量的值是点权的积,图的值是所有联通分量值的和。求i(i)

i不是割点容易求。如果是割点删掉就会形成很多新的联通分量,先把所有的点双连通分量求出来缩成一个新点,新点对联通分量里每个点都连边构造一个树,通过一次树dp求出每个点为根的子树的乘积以及每个点所有孩子子树的和。

trick:注意孤立点,新图的点数最多大概是原图的两倍。

#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#include <cmath>#include <map>#include <vector>#include <stack>using namespace std;#define maxn 400005#define maxm maxn*2#define mod 1000000007int n, m;int pre[maxn],dfs_clock,iscut[maxn],low[maxn],bcc_cnt,bccno[maxn];  vector<int>G[maxn],bcc[maxn];  struct Edge  {      int u,v;      Edge(int from,int to)      {          u=from;          v=to;      }  };  stack<Edge> S;  int tarjan (int u,int fa)  {      int lowu=pre[u]=++dfs_clock;      int child=0;      int Max = G[u].size ();    for(int i=0;i<Max;i++)      {          int v=G[u][i];          Edge e = Edge(u,v);          if(!pre[v])          {              S.push(e);              child++;              int lowv= tarjan (v,u);              lowu=min(lowv,lowu);              if(lowv>=pre[u])              {                  iscut[u]=true;                  bcc_cnt++;bcc[bcc_cnt].clear();                  for(;;)                  {                      Edge x = S.top();S.pop();                      if(bccno[x.u]!=bcc_cnt)                      {                          bcc[bcc_cnt].push_back(x.u);                          bccno[x.u]=bcc_cnt;                      }                      if(bccno[x.v]!=bcc_cnt)                      {                          bcc[bcc_cnt].push_back(x.v);                          bccno[x.v]=bcc_cnt;                      }                      if(x.u==u&&x.v==v) break;                  }              }          }          else if(pre[v]<pre[u]&&v!=fa)          {              S.push(e);              lowu=min(lowu,pre[v]);          }      }      if(fa<0&&child==1) iscut[u]=0;      return lowu;  }  void find_bcc ()  {      memset (pre,0,sizeof(pre));      memset (iscut,0,sizeof(iscut));      memset (bccno,0,sizeof(bccno));      dfs_clock=bcc_cnt=0;      for(int i=1; i <=n; i++)          if(!pre[i]) tarjan(i,-1);  }  long long a[maxn];struct node {    int v, next;}edge[maxm];int head[maxn], cnt;int degree[maxn];//用来判断孤立点int root[maxn];bool vis[maxn];long long sum[maxn], mul[maxn];void add_edge (int u, int v) {     edge[cnt].v = v, edge[cnt].next = head[u], head[u] = cnt++;}void dfs (int u, int fa, int rt) {    vis[u] = 1;    root[u] = rt;    sum[u] = 0;    mul[u] = a[u];    for (int i = head[u]; i != - 1; i = edge[i].next) {        int v = edge[i].v;        if (v == fa) continue;        dfs (v, u, rt);        sum[u] = (sum[u] + mul[v]) % mod;        mul[u] = mul[u] * mul[v] % mod;    }}long long extend_gcd(long long a,long long b,long long &x,long long &y)  {      if(a==0&&b==0) return -1;      if(b==0){x=1;y=0;return a;}      long long d=extend_gcd(b,a%b,y,x);      y-=a/b*x;      return d;  }  long long mod_rev(long long a,long long n)  {      long long x,y;      long long d=extend_gcd(a,n,x,y);      if(d==1) return (x%n+n)%n;      else return -1;  }  void solve () {    memset (head, -1, sizeof head);    cnt = 0;    for (int i = 1; i <= bcc_cnt; i++) {        int u = i+n, Max = bcc[i].size ();        a[u] = 1;        for (int j = 0; j < Max; j++) {             int v = bcc[i][j];             add_edge (u, v);            add_edge (v, u);        }    }    memset (vis, 0, sizeof vis);    long long tot = 0;    for (int i = 1; i <= n+bcc_cnt; i++) {        if (!vis[i]) {            dfs (i, -1, i);            tot = (tot+mul[i]) % mod;        }    }     long long ans = 0;    for (int i = 1; i <= n; i++) {        long long tmp = 0, niyuan;        if (!degree[i]) {            tmp = ((tot-a[i])%mod + mod) % mod;        }        else if (!iscut[i]) {            niyuan = mod_rev (a[i], mod);            long long cur = mul[root[i]] * niyuan % mod;            tmp = (tot - mul[root[i]] + cur);            tmp = (tmp % mod + mod) % mod;        }        else {            niyuan = mod_rev (mul[i], mod);            long long cur;             if (root[i] != i) {                cur = mul[root[i]] * niyuan % mod;            }            else                 cur = 0;            cur = (cur + sum[i]) % mod;            tmp = (tot - mul[root[i]] + cur);            tmp = (tmp % mod + mod) % mod;        }        ans = ans+1LL*i*tmp%mod;         ans %= mod;    }    printf ("%lld\n", ans);}int main () {    int t;    scanf ("%d", &t);    while (t--) {        scanf ("%d%d", &n, &m);        for (int i = 1; i <= n; i++) {            scanf ("%lld", &a[i]);            G[i].clear ();            degree[i] = 0;        }        for (int i = 0; i < m; i++) {            int u, v;            scanf ("%d%d", &u, &v);            degree[u]++, degree[v]++;            G[u].push_back (v);            G[v].push_back (u);        }        find_bcc ();        solve ();    }    return 0;}/*106 61 1 1 1 1 11 22 33 11 42 53 6*/
0 0