• HDU5739 Fantasia 树形dp + 点双缩点


    这个题当时打多校的时候有思路,但是代码能力差,没有写出来

    事后看zimpha巨巨的题解,看了觉得基本差不多

    核心思路:就是找出割点,然后变成森林,然后树形dp就可以搞了

                  关键就在重新构图上,缩完点以后,一个割点至少在两个点双里面,这个时候

                  把割点拿出来,分别和点双连边,也就是说,缩完的点双是不包含割点的,这个可以人为搞一下

                  (像有的点双里面只包含一个桥边,如果把割点拿出来,点双里面没有点了,这个时候把点双的权值积设为1就好)

                  然后说是树形dp,其实就是逆元搞一搞,这个很简单,树形dp只处理割点的答案

    注意:这个图不联通,这是一个点,还有孤立点,我一直wa在孤立点上,(我的点双模板只能解决至少包含两个点的连通图,这个题丰满了我的模板,感谢)

    #include <stdio.h>
    #include <iostream>
    #include <algorithm>
    #include <string.h>
    #include <vector>
    #include <math.h>
    #include <stack>
    #include <map>
    using namespace std;
    typedef long long LL;
    const int N = 1e5+5;
    const LL mod = 1e9+7;
    LL qpow(LL a,LL b){
      LL ret=1;
      while(b){
        if(b&1)ret=(ret*a)%mod;
        b>>=1;
        a=(a*a)%mod;
      }
      return ret;
    }
    int head[N<<1],tot,T,n,m;
    struct Edge{
      int u,v,next;
    }edge[N*4];
    void addedge(int u,int v){
      edge[tot].u=u;
      edge[tot].v=v;
      edge[tot].next=head[u];
      head[u]=tot++;
    }
    int low[N],dfn[N],clk,cnt,belbcc[N];
    bool iscut[N];
    vector<int>bcc[N],cut;
    stack<int>s;
    void init(){
      memset(dfn,0,sizeof(dfn));
      memset(head,-1,sizeof(head));
      memset(belbcc,0,sizeof(belbcc));
      tot=clk=cnt=0;
      cut.clear();
    }
    LL w[N],bccw[N<<1],ret[N],blkw[N<<1],zong;
    bool vis[N<<1];
    int blk,bel[N<<1];
    void dfs(int u,int f){
      dfn[u]=low[u]=++clk;
      int child=0;
      if(head[u]==-1){
        ++cnt;bcc[cnt].clear();
        bcc[cnt].push_back(u);
        belbcc[u]=cnt;
        return ;
      }
      for(int i=head[u];~i;i=edge[i].next){
         int to=edge[i].v;
         if(!dfn[to]){
            ++child;s.push(i);dfs(to,u);
            low[u]=min(low[u],low[to]);
            if(low[to]>=dfn[u]){
              iscut[u]=true;++cnt;int x;bcc[cnt].clear();
              do{
                 x=s.top();s.pop();
    
                 if(belbcc[edge[x].u]!=cnt){
                  bcc[cnt].push_back(edge[x].u);
                  belbcc[edge[x].u]=cnt;
                 }
    
                 if(belbcc[edge[x].v]!=cnt){
                  bcc[cnt].push_back(edge[x].v);
                  belbcc[edge[x].v]=cnt;
                 }
              }while(x!=i);
            } 
         }
         else if(dfn[to]<dfn[u]&&to!=f){
              s.push(i);
              low[u]=min(low[u],dfn[to]);
         }
      }
      if(!f&&child==1)iscut[u]=false;
      if(iscut[u])cut.push_back(n+u),bccw[n+u]=w[u];
    }
    void predfs(int u,int f){
        bel[u]=blk;blkw[blk]=blkw[blk]*bccw[u]%mod;
        vis[u]=true;
        for(int i=head[u];~i;i=edge[i].next){
            int v=edge[i].v;
            if(v==f)continue;
            predfs(v,u);
        }
    }
    LL treedp(int u,int f){
       LL pro=1,sum=0,tmp;
       vis[u]=false;
       for(int i=head[u];~i;i=edge[i].next){
          int v=edge[i].v;
          if(v==f)continue;
          tmp=treedp(v,u);
          pro=pro*tmp%mod;
          sum=(sum+tmp)%mod;
       }
       pro=pro*bccw[u]%mod;
       if(u>n){
         tmp=blkw[bel[u]];
         tmp=tmp*qpow(pro,mod-2)%mod;
         sum=(sum+tmp)%mod;
         tmp=zong-blkw[bel[u]];
         while(tmp<0)tmp+=mod; 
         ret[u-n]=(sum+tmp)%mod;
       }
       return pro; 
    }
    int main(){  
      scanf("%d",&T);
      while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)scanf("%I64d",&w[i]);
        init();
        for(int i=0;i<m;++i){
          int u,v;scanf("%d%d",&u,&v);
          addedge(u,v);addedge(v,u);
        }
        for(int i=1;i<=n;++i)if(!dfn[i])dfs(i,0);
        tot=0;memset(head,-1,sizeof(head));
        for(int i=1;i<=cnt;++i){
           bccw[i]=1;
           for(int j=0;j<bcc[i].size();++j){
              int u=bcc[i][j];
              if(iscut[u]) addedge(i,u+n),addedge(u+n,i);
              else  bccw[i]=bccw[i]*w[u]%mod;
           }
        }
        blk=0;
        for(int i=1;i<=cnt;++i)
         if(!vis[i]){++blk;blkw[blk]=1;predfs(i,0);}
        for(int i=0;i<cut.size();++i)
         if(!vis[cut[i]]){++blk;blkw[blk]=1;predfs(cut[i],0);}
        zong=0;
        for(int i=1;i<=blk;++i)zong=(zong+blkw[i])%mod;
        for(int i=1;i<=cnt;++i)
         if(vis[i])treedp(i,0);
        for(int i=0;i<cut.size();++i)
         if(vis[cut[i]])treedp(cut[i],0);
        LL ans=0;
        for(int i=1;i<=n;++i){
            if(iscut[i]){
               ans=(ans+1ll*i*ret[i]%mod)%mod;
               iscut[i]=false;
            }
            else{
               int k=belbcc[i];
               k=bel[k];
               LL ad=0;
               if(w[i]!=blkw[k])ad=blkw[k]*qpow(w[i],mod-2)%mod;
               LL tmp=zong-blkw[k];
               while(tmp<0)tmp+=mod;
               tmp=(tmp+ad)%mod;
               ans=(ans+1ll*i*tmp%mod)%mod;
            }
        }
        printf("%I64d
    ",ans);
      }
      return 0;
    }
    View Code
  • 相关阅读:
    js判断是否为数字
    MongoDB 复制集机制及原理
    MongoDB 聚合查询
    C#中时间相关知识点小结
    C#中的小数和百分数计算
    WPF使用VisualTreeHelper进行复杂命中测试
    WPF使用VisualTreeHelperj简单进行命中测试
    WPF Data Binding数据驱动
    WPF Binding中的RelativeSource属性
    WPF特效:流光动画效果
  • 原文地址:https://www.cnblogs.com/shuguangzw/p/5694952.html
Copyright © 2020-2023  润新知