题意:给一张无向点带有权无向图。定义连通图的权值为图中各点权的乘积,图的权值为其包含的各连通图的权和。设z_i为删除i点后图的权值,求$S = (\sum\limits_{i=1}^{n}i\cdot z_i) \text{ 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:才知道这个就是圆方树。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define mem(a) memset(a,0,sizeof(a))
#define rep(i,l,r) for (int i=(l),_=(r); i<=_; i++)
#define For(i,x) for (int i=h[x],k; i; i=nxt[i])
using namespace std; const int N=,mod=;
int T,n,m,tot,top,u,v,S,tim,bcc,d[N];
int w[N],p[N],val[N],ans[N],stk[N],low[N],dfn[N],bel[N];
bool vis[N];
inline void up(int &x,int y){ x+=y; if (x>=mod) x-=mod; } int ksm(int a,int b){
int res=;
for (; b; a=1ll*a*a%mod,b>>=)
if (b&) res=1ll*res*a%mod;
return res;
} struct E{
int cnt,h[N],to[N<<],nxt[N<<];
void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } void dfs(int x,int fa){
vis[x]=; val[x]=w[x]; bel[x]=tot;
For(i,x) if ((k=to[i])!=fa)
dfs(k,x),val[x]=1ll*val[x]*val[k]%mod;
} void DP(int x,int fa){
vis[x]=; ans[x]=(S-p[bel[x]]+mod)%mod;
For(i,x) if ((k=to[i])!=fa) DP(k,x),up(ans[x],val[k]);
up(ans[x],1ll*p[bel[x]]*ksm(val[x],mod-)%mod);
}
}G,G1; void tarjan(int x,int fa){
dfn[x]=low[x]=++tim; stk[++top]=x;
for (int i=G.h[x],k; i; i=G.nxt[i]) if ((k=G.to[i])!=fa){
if (dfn[k]) low[x]=min(low[x],dfn[k]);
else{
tarjan(k,x),low[x]=min(low[x],low[k]);
if (low[k]>=dfn[x]){
bcc++; w[n+bcc]=; int t;
while (){
t=stk[top]; //printf("%d %d\n",t,n+bcc);
G1.add(t,n+bcc); G1.add(n+bcc,t);
top--; if (t==k) break;
}
G1.add(x,n+bcc); G1.add(n+bcc,x);
}
}
}
} void init(){ rep(i,,n+bcc) G.h[i]=G1.h[i]=dfn[i]=d[i]=vis[i]=; G.cnt=G1.cnt=tot=top=tim=bcc=S=; } int main(){
freopen("hdu5739.in","r",stdin);
freopen("hdu5739.out","w",stdout);
for (scanf("%d",&T); T--; init()){
scanf("%d%d",&n,&m);
rep(i,,n) scanf("%d",&w[i]);
rep(i,,m) scanf("%d%d",&u,&v),G.add(u,v),G.add(v,u),d[u]++,d[v]++;
rep(i,,n) if (!dfn[i]) tarjan(i,);
rep(i,n+,n+bcc) if (!vis[i]) tot++,G1.dfs(i,),p[tot]=val[i],up(S,p[tot]);
rep(i,,n) if (!d[i]) up(S,w[i]);
rep(i,,n) if (!d[i]) ans[i]=(S-w[i]+mod)%mod;
//rep(i,1,n+bcc) printf("%d ",val[i]); puts("");
rep(i,,n+bcc) vis[i]=;
rep(i,n+,n+bcc) if (!vis[i]) G1.DP(i,);
//rep(i,1,n) printf("%d ",ans[i]); puts("");
int res=;
rep(i,,n) up(res,1ll*i*ans[i]%mod);
printf("%d\n",res);
}
return ;
}

[HDU5739]Fantasia(圆方树DP)的更多相关文章

  1. [BZOJ2125]最短路(圆方树DP)

    题意:仙人掌图最短路. 算法:圆方树DP,$O(n\log n+Q\log n)$ 首先建出仙人掌圆方树(与点双圆方树的区别在于直接连割边,也就是存在圆圆边),然后考虑点u-v的最短路径,显然就是:在 ...

  2. [BZOJ5463][APIO2018]铁人两项(圆方树DP)

    题意:给出一张图,求满足存在一条从u到v的长度大于3的简单路径的有序点对(u,v)个数. 做了上一题[HDU5739]Fantasia(点双连通分量+DP),这个题就是一个NOIP题了. 一开始考虑了 ...

  3. BZOJ1023:[SHOI2008]cactus仙人掌图(圆方树,DP,单调队列)

    Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus). 所谓简单回路就是指在图上不重复经过任何一个顶点 ...

  4. [BZOJ4316]小C的独立集(圆方树DP)

    题意:求仙人掌图直径. 算法:建出仙人掌圆方树,对于圆点直接做普通的树上DP(忽略方点儿子),方点做环上DP并将值直接赋给父亲. 建图时有一个很好的性质,就是一个方点在邻接表里的点的顺序正好就是从环的 ...

  5. 洛谷4630APIO2018铁人两项(圆方树+dp)

    QWQ神仙题啊(据说是今年第一次出现圆方树的地方) 首先根据题目,我们就是求对于每一个路径\((s,t)\)他的贡献就是两个点之间的点数,但是图上问题我并没有办法很好的解决... 这时候考虑圆方树,我 ...

  6. Luogu4630 APIO2018 Duathlon 圆方树、树形DP

    传送门 要求的是一条按顺序经过\(s,t,c\)三个点的简单路径.简单路径的计数问题不难想到点双联通分量,进而使用圆方树进行求解. 首先将原图缩点,对于一个大小为\(size\)的点双联通分量内,在这 ...

  7. [APIO2018] Duathlon 铁人两项 圆方树,DP

    [APIO2018] Duathlon 铁人两项 LG传送门 圆方树+简单DP. 不会圆方树的话可以看看我的另一篇文章. 考虑暴力怎么写,枚举两个点,答案加上两个点之间的点的个数. 看到题面中的一句话 ...

  8. [APIO2018]铁人两项——圆方树+树形DP

    题目链接: [APIO2018]铁人两项 对于点双连通分量有一个性质:在同一个点双里的三个点$a,b,c$,一定存在一条从$a$到$c$的路径经过$b$且经过的点只被经过一次. 那么我们建出原图的圆方 ...

  9. loj2587 「APIO2018」铁人两项[圆方树+树形DP]

    主要卡在一个结论上..关于点双有一个常用结论,也经常作为在圆方树/简单路径上的良好性质,对于任意点双内互不相同的三点$s,c,t$,都存在简单路径$s\to c\to t$,证明不会.可以参见clz博 ...

随机推荐

  1. POJ2516:Minimum Cost(最小费用最大流)

    Minimum Cost Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 19088   Accepted: 6740 题目链 ...

  2. HDU 多校对抗赛 C Triangle Partition

    Triangle Partition Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Oth ...

  3. java过滤器和监听器详解

    过滤器 1.Filter工作原理(执行流程) 当客户端发出Web资源的请求时,Web服务器根据应用程序配置文件设置的过滤规则进行检查,若客户请求满足过滤规则,则对客户请求/响应进行拦截,对请求头和请求 ...

  4. javascript错误处理(转)

    1.onerror事件处理函数onerror事件处理函数是第一个用来协助javascript处理错误的机制.页面上出现异常时,error事件便在window对象上触发.例如: <html> ...

  5. elemetUi 组件--el-upload

    [需求]实现上传Excel文件,在上传到服务器时,还要附加一个参数,在请求上传文件接口前,先要进行文件格式判断. [知识点] 1.el-upload 官方文档中,主要用到了以下属性: data 可选参 ...

  6. [洛谷P2420] 让我们异或吧

    题目链接:让我们异或吧 题目描述 异或是一种神奇的运算,大部分人把它总结成不进位加法. 在生活中…xor运算也很常见.比如,对于一个问题的回答,是为1,否为0.那么: (A是否是男生 )xor( B是 ...

  7. 【Foreign】魔法 [组合数][质因数分解]

    魔法 Time Limit: 10 Sec  Memory Limit: 256 MB Description Input Output 仅一行一个整数表示答案. Sample Input 4 10 ...

  8. spring自定义参数绑定(日期格式转换)

    spring参数绑定时可能出现 BindException(参数绑定异常),类似下面的日期绑定异常(前台传过来是String类型,实际的pojo是Date类型) default message [Fa ...

  9. Splunk Power User认证

    课程介绍 | 通过 Splunk Fundamentals Part 1 课程考试 | 获取splunk certificate user 证书 | 课程为14节课+课后实验环境+课后习题 | 课程有 ...

  10. 说出JAVA中一些常用的类,包,接口,请各举5个~~~

    类:1.java.lang.Object2.java.lang.String3.java.lang.System4.java.io.file5.java.io.FileInputStream6.jav ...