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

事后看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+;
const LL mod = 1e9+;
LL qpow(LL a,LL b){
LL ret=;
while(b){
if(b&)ret=(ret*a)%mod;
b>>=;
a=(a*a)%mod;
}
return ret;
}
int head[N<<],tot,T,n,m;
struct Edge{
int u,v,next;
}edge[N*];
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,,sizeof(dfn));
memset(head,-,sizeof(head));
memset(belbcc,,sizeof(belbcc));
tot=clk=cnt=;
cut.clear();
}
LL w[N],bccw[N<<],ret[N],blkw[N<<],zong;
bool vis[N<<];
int blk,bel[N<<];
void dfs(int u,int f){
dfn[u]=low[u]=++clk;
int child=;
if(head[u]==-){
++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==)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=,sum=,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-)%mod;
sum=(sum+tmp)%mod;
tmp=zong-blkw[bel[u]];
while(tmp<)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=;i<=n;++i)scanf("%I64d",&w[i]);
init();
for(int i=;i<m;++i){
int u,v;scanf("%d%d",&u,&v);
addedge(u,v);addedge(v,u);
}
for(int i=;i<=n;++i)if(!dfn[i])dfs(i,);
tot=;memset(head,-,sizeof(head));
for(int i=;i<=cnt;++i){
bccw[i]=;
for(int j=;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=;
for(int i=;i<=cnt;++i)
if(!vis[i]){++blk;blkw[blk]=;predfs(i,);}
for(int i=;i<cut.size();++i)
if(!vis[cut[i]]){++blk;blkw[blk]=;predfs(cut[i],);}
zong=;
for(int i=;i<=blk;++i)zong=(zong+blkw[i])%mod;
for(int i=;i<=cnt;++i)
if(vis[i])treedp(i,);
for(int i=;i<cut.size();++i)
if(vis[cut[i]])treedp(cut[i],);
LL ans=;
for(int i=;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=;
if(w[i]!=blkw[k])ad=blkw[k]*qpow(w[i],mod-)%mod;
LL tmp=zong-blkw[k];
while(tmp<)tmp+=mod;
tmp=(tmp+ad)%mod;
ans=(ans+1ll*i*tmp%mod)%mod;
}
}
printf("%I64d\n",ans);
}
return ;
}

HDU5739 Fantasia 树形dp + 点双缩点的更多相关文章

  1. hdu 4612 Warm up 双连通+树形dp思想

    Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total S ...

  2. HDU4612(Warm up)2013多校2-图的边双连通问题(Tarjan算法+树形DP)

    /** 题目大意: 给你一个无向连通图,问加上一条边后得到的图的最少的割边数; 算法思想: 图的边双连通Tarjan算法+树形DP; 即通过Tarjan算法对边双连通缩图,构成一棵树,然后用树形DP求 ...

  3. HDU 2242 考研路茫茫—空调教室 (边双连通+树形DP)

    <题目链接> 题目大意: 给定一个连通图,每个点有点权,现在需要删除一条边,使得整张图分成两个连通块,问你删除这条边后,两联通块点权值和差值最小是多少. 解题分析: 删除一条边,使原连通图 ...

  4. hdu 2242双联通分量+树形dp

    /*先求出双联通缩点,然后进行树形dp*/ #include<stdio.h> #include<string.h> #include<math.h> #defin ...

  5. HDU5739 Fantasia(点双连通分量 + Block Forest Data Structure)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5739 Description Professor Zhang has an undirect ...

  6. 洛谷 P2515 [HAOI2010]软件安装(缩点+树形dp)

    题面 luogu 题解 缩点+树形dp 依赖关系可以看作有向边 因为有环,先缩点 缩点后,有可能图不联通. 我们可以新建一个结点连接每个联通块. 然后就是树形dp了 Code #include< ...

  7. 【BZOJ2427】[HAOI2010] 软件安装(缩点+树形DP)

    点此看题面 大致题意: 有\(N\)个软件,每个软件有至多一个依赖以及一个所占空间大小\(W_i\),只有当一个软件的直接依赖和所有的间接依赖都安装了,它才能正常工作并造成\(V_i\)的价值.求在容 ...

  8. 洛谷P2515 [HAOI2010]软件安装(tarjan缩点+树形dp)

    传送门 我们可以把每一个$d$看做它的父亲,这样这个东西就构成了一个树形结构 问题是他有可能形成环,所以我们还需要一遍tarjan缩点 缩完点后从0向所有入度为零的点连边 然后再跑一下树形dp就行了 ...

  9. HDU 2242 连通分量缩点+树形dp

    题目大意是: 所有点在一个连通图上,希望去掉一条边得到两个连通图,且两个图上所有点的权值的差最小,如果没有割边,则输出impossible 这道题需要先利用tarjan算法将在同一连通分量中的点缩成一 ...

随机推荐

  1. 获取SqlDataReader的列名

    SqlConnection thisConnection = new SqlConnection(ConfigurationManager.AppSettings["ConnectionSt ...

  2. 分享一个安装PE到硬盘的软件

    Ton8pe_v5.0下载地址:http://pan.baidu.com/share/link?shareid=424350&uk=4180312589 电脑是XP,有光驱,但是没win8.1 ...

  3. 李洪强漫谈iOS开发[C语言-039]-剪刀石头布

     李洪强漫谈iOS开发[C语言-039]-剪刀石头布

  4. ArcGIS 10.1 for Desktop新特性之地理标记照片

    转自:http://blog.csdn.net/esrichinacd/article/details/7730825 地理标记照片是指带有地理位置信息的照片,通常通过内置GPS的数码相机或智能手机拍 ...

  5. 41. First Missing Positive

    题目: Given an unsorted integer array, find the first missing positive integer. For example,Given [1,2 ...

  6. renameTo()方法的用法

    使用renameTo()方法,可以将文件data.txt从C:\JavaApp\IOTest1\目录移动到C:\目录,并改名为newdata.txt import java.io.File; //将文 ...

  7. Android 虚线分割Shape

    <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http: ...

  8. Java集合框架学习笔记

    集合类的由来:对象用于封装特有数据,对象多了需要存储,如果对象的长度不确定,就使用集合存储. 集合特点1.用于存储对象的容器.2.集合的长度可变.3.集合中不可以存储基本类型 集合容器因为内部的数据结 ...

  9. Android上常见度量单位【xdpi、hdpi、mdpi、ldpi】解读

    术语和概念  屏幕尺寸  屏幕的物理尺寸,以屏幕的对角线长度作为依据(比如 2.8寸, 3.5寸).  简而言之, Android把所有的屏幕尺寸简化为三大类:大,正常,和小.  程序可以针对这三种尺 ...

  10. 用imagemagick和tesseract-ocr破解简单验证码

    用imagemagick和tesseract-ocr破解简单验证码 Tesseract-ocr据说辨识程度是世界排名第三,可谓神器啊. 准备工作: 1.安装tesseract-ocr sudo apt ...