2016多校 #2 1006 Fantasia

http://acm.hdu.edu.cn/showproblem.php?pid=5739

已知一个无向图,每个结点有价值a[i]。一个连通图的价值定义为其所有结点价值之积;一个不连通图的价值为其所有连通分量的价值之和。

分别求删除每一个点后图的剩余部分的价值。n<=1e5,m<=2*1e5.

首先,原图可能有若干连通分量,这种情况很好处理。下面只对一个连通分量进行说明。

首先,删除一个点后图可能会分裂成若干部分,所以我们要对割点和非割点分别处理。

首先用tarjan求出所有割点,在此过程中即可顺便求出删除每个割点后,其所在原连通分量所分裂成的子图的价值。这需要我们对tarjan过程的dfs树

有充分了解。对图中的某一个割点u,将u删除后图必定分割成大于一个的分支。在dfs树中,每一个分支要么对应u的一棵子树,要么是除去u这棵子树以外的部分。

我们用一个全局变量mul,在dfs过程中,每到一个结点就将mul乘此结点的价值,如果对结点u,发现其在dfs树中的子结点v,low[v]<=dfn[u],则以v为根的子树就是删除

u后的一个分支。记对v进行dfs之前的mul为mem,则此分支的价值就是当前的mul/mem。将所有分支价值相加。

对于非dfs树根节点的割点u,其分支还包括除去dfs树中以u为根的子树的部分,用总的mul除以其子树那一部分之积即可。

这样查询就很简单了。

需要注意的是如果某连通分量只有一个结点,删除后此分量消失,若不特殊处理很容易将其价值按1计算。注意。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <string>
  4 #include <cstring>
  5 #include <algorithm>
  6 #include <cmath>
  7 #include <vector>
  8 using namespace std;
  9
 10 const int N = 100010,M = 200010,mod = 1e9+7;
 11 int color,tot,p,n,m,start;
 12 int dfn[N],low[N],spot[M*2],nex[M*2],head[N],c[N];
 13 long long all,mul,a[N],f[N],size[N],chmul[N];
 14 bool v[N],is[N];
 15
 16 vector<int> have[N];
 17
 18 void add(int x,int y) {
 19     nex[++p] = head[x]; head[x] = p; spot[p] = y;
 20     nex[++p] = head[y]; head[y] = p; spot[p] = x;
 21 }
 22
 23 long long mypow(long long a,int b)
 24 {
 25     long long c = 1;
 26     for(; b; b>>=1) {
 27         if(b&1) c = c*a%mod;
 28         a = a*a%mod;
 29     }
 30     return c;
 31 }
 32
 33 long long ni(long long x)
 34 {
 35     return mypow(x, mod-2);
 36 }
 37
 38 void tarjan(int x)
 39 {
 40     low[x] = dfn[x] = ++tot;
 41     v[x] = 1;
 42     c[x] = color;
 43     have[color].push_back(x);
 44     mul = mul*a[x]%mod;
 45     long long mem;
 46     int tp,y,cnt = 0;
 47     for(tp = head[x]; tp; tp = nex[tp])
 48     {
 49         y = spot[tp];
 50         if(!dfn[y])
 51         {
 52             mem = mul;
 53             tarjan(y);
 54             low[x] = min(low[x], low[y]);
 55             if(low[y]>=dfn[x]) {
 56                 cnt++;
 57                 long long temp = mul*ni(mem)%mod;
 58                 f[x] = (f[x]+temp)%mod;
 59                 (chmul[x] *= temp ) %= mod;
 60             }
 61         }
 62         else if(v[y])
 63             low[x] = min(low[x], dfn[y]);
 64     }
 65     if(start==x && cnt>1 || start!=x && cnt)
 66         is[x] = 1;
 67 }
 68
 69 long long cal(int x)
 70 {
 71     long long temp,ret;
 72     temp = (all-size[c[x]])%mod;
 73     if(!is[x]) {
 74         if(have[c[x]].size()==1)
 75             ret = temp;
 76         else
 77             ret = (temp+size[c[x]]*ni(a[x]))%mod;
 78     }
 79     else ret = temp+f[x];
 80     return (ret%mod+mod)%mod;
 81 }
 82
 83 int main()
 84 {
 85     int test,i,j,x,y;
 86     for(cin >> test; test--; ) {
 87         cin >> n >> m;
 88         for(i = 1; i<=n; i++)
 89             scanf("%I64d", &a[i]);
 90
 91         for(i = 1; i<=n; i++)
 92             head[i] = 0;
 93         p = 0;
 94
 95         for(i = 1; i<=m; i++) {
 96             scanf("%d%d", &x,&y);
 97             add(x,y);
 98         }
 99
100         for(i = 1; i<=n; i++) {
101             f[i] = 0, chmul[i] = 1;
102             is[i] = 0;
103             dfn[i] = low[i] = v[i] = c[i] = 0;
104         }
105
106         tot = all = color = 0;
107         for(i = 1; i<=n; i++)
108             have[i].clear();
109         for(i = 1; i<=n; i++)
110             if(!dfn[i]) {
111                 color++;
112                 mul = 1; start = i; tarjan(i);
113                 all = (all+mul)%mod;
114                 size[color] = mul;
115                 for(j = 0; j<have[color].size(); j++)
116                 {
117                     x = have[color][j];
118                     if(x!=start) {
119                         (f[x] += mul*ni(chmul[x]*a[x]%mod)) %= mod;
120                     }
121                 }
122             }
123         long long ans = 0;
124         for(i = 1; i<=n; i++) {
125             ans = (ans+i*cal(i))%mod;
126         }
127         printf("%I64d\n", ans);
128     }
129     return 0;
130 }

时间: 2024-11-05 22:35:36

2016多校 #2 1006 Fantasia的相关文章

HDU 4940(杭电多校#7 1006) Destroy Transportation system(瞎搞)

题目地址:HDU 4940 当时这个题一看就看出来了是网络流的最小割,然后就一直在想建图..然后突然发现,应该要让T集合的数目最少,不然只要有两个,那这两个的每一个都可以跑到S集合,使得T集合变小.那就只能是1个了.然后..枚举就好了..但是虽然觉得这么做肯定没错..但是不敢敲..因为当时都3个小时了才只有10个队过了...后来又想了几遍后觉得这样没错,就写完交上了.果然AC... 代码如下: #include <iostream> #include <cstdio> #inclu

2016 华科校赛 B. And

// 2016 华科校赛 B. And http://acm.hust.edu.cn/problem/show/1672 题目描述 给出 a[1], ..., a[n].查询 t[1], ... t[m],问有多少 a[] 的子序列的按位与是 t[]. 输入 多组测试,EOF 结束. n a[] m t[] 1 ≤ n ≤ 1e6 1 ≤ m ≤ (1 << 20) 1 ≤ a[i] ≤ (1 << 20) 1 ≤ t[i] ≤ (1 << 20) 输出 输出一行,每组

Nice boat(多校联合1006)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 1    Accepted Submission(s): 0 Problem Description There is an old country and the king fell in love with a devil. The devil always

2016弱校联萌十一专场10.3 遗憾题合集

http://acm-icpc.aitea.net/index.php?2016%2FPractice%2F%E6%A8%A1%E6%93%AC%E5%9C%B0%E5%8C%BA%E4%BA%88%E9%81%B8%2F%E8%AC%9B%E8%A9%95 C.We don't wanna work! @siludose 你要的代码,做好了参考看 SB模拟,xjb模拟 #include <iostream> #include <algorithm> #include <st

2016 SCNUCPC 校赛非官方题解

我要举报本次校赛出题人的消极出题!!! A. 树链剖分数据结构板题 B. The background of water problem 题目大意(大写加粗的水题):给定$N$个学生和他们$K$个科目的成绩$S_i$,再给出各科目$K_i$的权重顺序$Q_i$,求排名之后,拥有id为$X$的是哪个学生. 基本思路:虽然$K$只有$10$,$S$只有$100$,但有M组查询,所以当然不能开个long long去hash每个学生.我们简单点,开个结构体,排个序,就好了. 参考代码: 官方代码(将成绩

2017 多校训练 1006 Function

Function Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 273    Accepted Submission(s): 99 Problem Description You are given a permutation a from 0 to n−1 and a permutation b from 0 to m−1. De

【2016多校】T3 subset(分块,DP)

1 var dp:array[0..300,0..300]of longint; 2 s1,s2,n,i,x,j:longint; 3 ch:string; 4 5 procedure dfs1(var s1,s2:longint;k,s:longint); 6 begin 7 if k>7 then 8 begin 9 inc(dp[s1,s]); 10 exit; 11 end; 12 if s2 and (1<<k)>0 then dfs1(s1,s2,k+1,s+(1<

2016弱校联萌十一专场10.2

F.floyd-warshell 20000个点,距离为1的所有边求最短路 感觉就是单纯的生成树求最短路(最近公共祖先) 然后把去掉的边还原 把涉及的点bfs一下拼出最短路 #include<cstdio> #include<algorithm> #include<cstring> #define F(i,a,b) for(int i=a;i<=b;i++) #define mst(a,b) memset(a,b,sizeof(a)) using namespac

HDU 5858 Hard problem (2016 多校训练#10 1002)

题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5858 题意:给出下图和正方形边长,求阴影部分面积. 分析:数学题,总之就是割来割去推公式,比赛时是队友打的,拿他代码直接贴了. 具体分析可以看这里. http://www.zybang.com/question/1301cb472211299680f8d4796e7dc797.html 代码: #include<cstdio> #include<cmath> #includ