[POI2008]BLO-Blockade 题解

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值