[HDU 5739] Fantasia (点双联通分量 + Block Forest Data Structure)
来源:互联网 发布:排课表软件 编辑:程序博客网 时间:2024/05/17 04:05
HDU - 5739
给定一张无向图,每个点有个点权
一个图的权值计算为,现将同一联通分量的点权相乘
再将不同联通分量的点权相加
求图割去一个点后的权值
其中对于哪些非关节点,权值比较好计算
而对于关节点,割去之后图比较复杂
所以要用到一个叫做 Block Forest Data Structure的建图方式
首先求出图中的点双联通分量,
对于每一个点双,新建一个点向其中所有点连边
新图就会变成一个森林,其中非关节点是叶子节点,
而关节点和新建的点是内点
然后用树形统计一下每个点儿子的乘积和以及子树的乘积和
有一个trick就是有孤点的情况,孤点不会被记入点双,
所以特判一下,对于孤点直接计算答案即可
#pragma comment(linker, "/STACK:102400000,102400000")#include <cstdio>#include <iostream>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <cctype>#include <map>#include <set>#include <queue>#include <bitset>using namespace std;typedef pair<int,int> Pii;typedef long long LL;typedef unsigned long long ULL;typedef double DBL;typedef long double LDBL;#define MST(a,b) memset(a,b,sizeof(a))#define CLR(a) MST(a,0)#define SQR(a) ((a)*(a))#define PCUT puts("----------")const int maxn=2e5+10, maxm=2e5+10;const LL MOD=1e9+7;struct Graph{ int ndn, edn, last[maxn<<1]; int u[maxm<<1], v[maxm<<1], nxt[maxm<<1]; LL pval[maxn<<1], allw[maxn<<1]; void init(int _n){ ndn=_n; edn=0; MST(last,-1); } void adde(int _u, int _v) { u[edn]=_u; v[edn]=_v; nxt[edn]=last[_u]; last[_u]=edn++; }};struct Tarjan{ Graph *G; int dfst, dfsn[maxn], lowv[maxn]; int dcc_cnt, skt, stak[maxn], iscut[maxn]; bool ins[maxn]; vector<int> dcc[maxn]; int DCC(); int dfs(int,int); int tot; int BlockForest(); LL *ans, *cans, allw; LL sum[maxn<<1], pro[maxn<<1]; bool vis[maxn]; int solve(Graph*,LL*,LL*,LL); int calc(int,int);};int N,M;Graph G;Tarjan tar;LL ans[maxn<<1], cans[maxn<<1], allw;bool previs[maxn];void precom(int,LL&);int prevec[maxn], pcnt;LL Pow(LL,LL,LL);int main(){ #ifdef LOCAL freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout); #endif int T; scanf("%d", &T); for(int ck=1; ck<=T; ck++) { scanf("%d%d", &N, &M); G.init(N); for(int i=1; i<=N; i++) scanf("%lld", &G.pval[i]); for(int i=0, u, v; i<M; i++) { scanf("%d%d", &u, &v); G.adde(u,v); G.adde(v,u); } CLR(ans); CLR(cans); CLR(previs); allw=0; for(int i=1; i<=N; i++) if(!previs[i]) { pcnt=0; LL getv=1; precom(i,getv); for(int j=0; j<pcnt; j++) cans[prevec[j]] = getv; allw = (allw+getv)%MOD; } tar.solve(&G,ans,cans,allw); LL res=0; for(int i=1; i<=N; i++) res = (res+i*ans[i]%MOD)%MOD; printf("%lld\n", (res+MOD)%MOD); } return 0;}void precom(int u,LL &getv){ previs[u]=1; getv = getv*G.pval[u]%MOD; prevec[pcnt++] = u; for(int e=G.last[u],v; ~e; e=G.nxt[e]) { v=G.v[e]; if(previs[v]) continue; precom(v,getv); }}int Tarjan::solve(Graph *g, LL _ans[], LL _cans[], LL _allw){ G = g; ans = _ans; cans=_cans, allw = _allw; DCC(); BlockForest(); CLR(vis); for(int i=1; i<=dcc_cnt; i++) if(!vis[i]) calc(tot+i,-1); return 0;}int Tarjan::calc(int u, int f){ if(u>tot) vis[u-tot]=1; sum[u]=0; pro[u]=G->pval[u]; for(int e=G->last[u],v; ~e; e=G->nxt[e]) { v=G->v[e]; if(v==f) continue; calc(v, u); sum[u] = (sum[u]+pro[v])%MOD; pro[u] = (pro[u]*pro[v])%MOD; } if(u<=tot) ans[u] = ((allw-cans[u])%MOD + sum[u] + cans[u]*Pow(pro[u], MOD-2, MOD)%MOD) %MOD; return 0;}int Tarjan::BlockForest(){ tot=G->ndn; G->init(tot+dcc_cnt); for(int i=1, u; i<=dcc_cnt; i++) { u=tot+i; G->pval[u] = 1; for(int j=0; j<(int)dcc[i].size(); j++) { G->adde(u, dcc[i][j]); G->adde(dcc[i][j], u); } dcc[i].clear(); } return tot;}int Tarjan::DCC(){ dfst=0; CLR(dfsn); CLR(lowv); dcc_cnt=0; skt=0; CLR(stak); CLR(ins); CLR(iscut); for(int i=1; i<=G->ndn; i++) if(!dfsn[i]) dfs(i,-1); return 0;}int Tarjan::dfs(int u,int f){ lowv[u] = dfsn[u] = ++dfst; int child=0; for(int e=G->last[u], v; ~e; e=G->nxt[e]) { v=G->v[e]; if(v==f) continue; child++; if(!dfsn[v]) { stak[++skt] = e>>1; dfs(v,u); lowv[u] = min(lowv[u], lowv[v]); if(lowv[v] >= dfsn[u]) { iscut[u]=1; ++dcc_cnt; do { int te = stak[skt]<<1; dcc[dcc_cnt].push_back(G->u[te]); dcc[dcc_cnt].push_back(G->v[te]); } while( (e>>1) != stak[skt--]); sort(dcc[dcc_cnt].begin(), dcc[dcc_cnt].end()); dcc[dcc_cnt].erase( unique(dcc[dcc_cnt].begin(), dcc[dcc_cnt].end()), dcc[dcc_cnt].end()); } } else if(dfsn[v] < dfsn[u]) { stak[++skt] = e>>1; lowv[u] = min(lowv[u], dfsn[v]); } } if(f==-1 && child<=1) iscut[u]=0; if(f==-1 && child==0) { ans[u] = (allw-G->pval[u])%MOD; } return 0;}LL Pow(LL x, LL n, LL p){ LL res=1; while(n) { if(n&1) res=res*x%p; x=x*x%p; n>>=1; } return res%p;}
0 0
- [HDU 5739] Fantasia (点双联通分量 + Block Forest Data Structure)
- Uva 10765 Doves and bombs (点双联通分量 + Block Forest Data Structure)
- hdu 5739(点双联通分量 )
- HDU 5739 点-双联通分量
- 点双联通分量
- 【HDU 5739】Fantasia(点双连通+dfs)
- HDU 5739 Fantasia(点双连通分量+树形DP)
- hdu 5739 Fantasia(Tarjan,割点)
- hdu 4612 Warm up (边双联通分量缩点)
- HDU 3394 Railway (点双联通分量+桥)
- 点双联通分量模板
- 割点,割边,强联通分量,点双联通分量,边双联通分量
- UVALive5796点双联通分量or边双联通分量
- 点双联通分量和边双联通分量小结
- HDU 4738 双联通分量
- 双联通分量---点双联通,边双联通 (模板)
- hdu 5739 Fantasia
- HDU 5739 Fantasia(tarjan)
- 简单dp算法——Milking Time
- JSP的7个动作指令
- 48.自定义邮件模板
- 显示在文本框中输入的信息
- redis集群的合纵和连横
- [HDU 5739] Fantasia (点双联通分量 + Block Forest Data Structure)
- 快速排序算法的时间复杂度分析[详解Master method]
- linux命令link汇总
- spring技术框架基础知识三属性编辑器
- HDU 1233 还是畅通工程 最小生成树 Prim模板的应用
- yum方式安装ffmpeg步骤
- 3.8 编写一个程序打印如图 3.1 所示的 n 阶杨辉三角形,其中 n 由用户输入,该值不 能大于 13。
- ”The virtual device got no IP address.“的解决
- HDU1213 How Many Tables 并查集