poi~
原题目
点无非分为两种
割点 & 非割点
根据题目可得 , 对于非割点答案显然是
ans = (n - 1) * 2;
那么对于割点怎么处理答案呐?
把她分成两部分处理
对于一个点 fa
他的所有子树(搜索树中)的 size 互相乘起来 , 因为子树间互相断开不能联系
然后把所有子树的 size 加起来得 sum , 然后 ans += sum * (n - sum - 1) , 因为所有的子树都无法与外界联系
因为不算 fa 本身 , 所以是 (n - sum - 1) 而非 (n - sum)
但是对于一个点对 (a, b) 断开了显然有 (b, a) 也断开
我们只处理了一个 , 所以最后要把答案乘二
最后对于割点也要再加上 (n - 1) * 2 来处理上文没有处理的 fa 的情况
至于怎么得到 size , 在tarjan处理割点的时候处理一下就可以了
代码:
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<iostream> 6 #include<algorithm> 7 #define APART puts("----------------------") 8 #define debug 1 9 #define FILETEST 1 10 #define inf 500010 11 #define ll long long 12 #define ha 998244353 13 #define INF 0x7fffffff 14 #define INF_T 9223372036854775807 15 #define DEBUG printf("%s %d\n",__FUNCTION__,__LINE__) 16 17 namespace chino{ 18 19 inline void setting(){ 20 #if FILETEST 21 freopen("_test.in", "r", stdin); 22 freopen("_test.me.out", "w", stdout); 23 #endif 24 return; 25 } 26 27 inline int read(){ 28 char c = getchar(), up = c; int num = 0; 29 for(; c < ‘0‘ || c > ‘9‘; up = c, c = getchar()); 30 for(; c >= ‘0‘ && c <= ‘9‘; num = (num << 3) + (num << 1) + (c ^ ‘0‘), c = getchar()); 31 return up == ‘-‘ ? -num : num; 32 } 33 34 int n, m; 35 int cntJ, cntE; 36 int cut[inf], size[inf]; 37 ll ans[inf]; 38 int dfn[inf], low[inf]; 39 int head[inf]; 40 struct Edge{ 41 int to; 42 int next; 43 }e[inf << 1]; 44 45 inline void AddEdge(int from, int to){ 46 ++cntE; 47 e[cntE].to = to; 48 e[cntE].next = head[from]; 49 head[from] = cntE; 50 return; 51 } 52 53 void tarjan(int now, int root){ 54 dfn[now] = low[now] = ++cntJ; 55 int index = 0, sum = 0; 56 size[now] = 1; 57 for(int i = head[now]; i; i = e[i].next){ 58 int to = e[i].to; 59 if(dfn[to] == 0){ 60 tarjan(to, 0); 61 low[now] = std::min(low[now], low[to]); 62 size[now] += size[to]; 63 if(root) 64 ++index; 65 if(low[to] >= dfn[now]){ 66 if(root == 0) 67 cut[now] = 1; 68 ans[now] += 1ll * size[to] * sum; 69 sum += size[to]; 70 } 71 } else 72 low[now] = std::min(low[now], dfn[to]); 73 } 74 if(root && index >= 2) 75 cut[now] = 1; 76 ans[now] += 1ll * sum * (n - sum - 1); 77 return; 78 } 79 80 inline int main(){ 81 n = read(); 82 m = read(); 83 for(int i = 1; i <= m; i++){ 84 int u = read(); 85 int v = read(); 86 AddEdge(u, v); 87 AddEdge(v, u); 88 } 89 for(int i = 1; i <= n; i++){ 90 if(dfn[i] == 0) 91 tarjan(i, 1); 92 } 93 for(int i = 1; i <= n; i++){ 94 if(cut[i] == 0) 95 ans[i] = 0; 96 ans[i] += n - 1; 97 ans[i] <<= 1; 98 printf("%lld\n", ans[i]); 99 } 100 return 0; 101 } 102 103 }//namespace chino 104 105 int main(){return chino::main();}
最后瞎说几句(小声bb)
自己一开始想了个假做法结果做了好长时间zbl
原文地址:https://www.cnblogs.com/chiarochinoful/p/problem-poi2008-BLO-Blockade.html
时间: 2024-10-09 22:34:23