• [POI2008]BLO-Blockade


    题目传送门

    题意:给定一张无向图,求每个点被封锁之后有多少个有序点对$(x,y)(x!=y,1<=x,y<=n)$满足$x$无法到达$y$。

    题目强调了所有村庄都相互可达。

    首先会想到割顶,因为如果删去割顶,就会导致图的连通块增加。反之不变。

    不是割顶答案就应该是$(n-1)*2$。因为连通块没有增加意味着除去该点其他任意点对都可直接或间接可达,不可达的是该点与其他点之间来回的连接。

    如果是割顶,实际上答案就是上面的基础上加上各个连通块之间的答案。

    但如果删去割顶再判断复杂度变成$O(n^2)$会$TLE$。

    于是我们在$Tarjan$的过程中顺便求下。

    如果删去这个点有$n$个连通块,每个的大小为$son_i$,那么答案应该是$2sum_{i=1}^n sum_{j=i+1}^n son_i imes son_j$。

    变形下也就是$son_i$要与所有$son_j,j={ 1,2,..,i-1}$相乘。

    所以我们每统计一个连通块只要维护$son_i$和$sum_{j=1}^{i-1}son_j$即可。

    在$Tarjan$过程中,就是$dfs$其相连结点时,如果子结点及其后继结点不能访问到此结点的祖先结点则说明该结点底下是连通块,应该统计。

    最后会剩余该结点的祖先结点,它们会构成连通块,大小为$n-sum_{i=1}^n son_i - 1$。

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 #define re register
     6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
     7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
     8 #define maxx(a, b) a = max(a, b);
     9 #define minn(a, b) a = min(a, b);
    10 #define LL long long
    11 #define inf (1 << 30)
    12 
    13 inline int read() {
    14     int w = 0, f = 1; char c = getchar();
    15     while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
    16     while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar();
    17     return w * f;
    18 }
    19 
    20 const int maxn = 1e5 + 10, maxm = 5e5 + 10;
    21 
    22 struct Edge {
    23     int u, v, pre;
    24 };
    25 
    26 struct Graph {
    27     Edge edges[maxm << 1];
    28     int n, m;
    29     int G[maxn];
    30     int dfs_clock, low[maxn], pre[maxn], iscut[maxn];
    31     LL sum[maxn], sc[maxn], ans[maxn];
    32     void init(int n) {
    33         this->n = n;
    34         m = 0;
    35         memset(G, 0, sizeof(G));
    36     }
    37     void Add(int u, int v) {
    38         edges[++m] = (Edge){u, v, G[u]};
    39         G[u] = m;
    40     }
    41     // int tag[maxn], tot[maxn];
    42     void dfs(int u, int fa) {
    43         low[u] = pre[u] = ++dfs_clock;
    44         int child = 0;
    45         for (register int i = G[u]; i; i = edges[i].pre) {
    46             int v = edges[i].v;
    47             if (!pre[v]) {
    48                 child++;
    49                 dfs(v, u);
    50                 if (low[v] >= pre[u]) {
    51                     ans[u] += sum[u] * sc[v];
    52                     sum[u] += sc[v];
    53                 }
    54                 sc[u] += sc[v];
    55                 minn(low[u], low[v]);
    56                 if (low[v] >= pre[u]) iscut[u] = 1;
    57             } else {
    58                 if (v != fa) 
    59                     minn(low[u], pre[v]);
    60             }
    61         }
    62         if (u == fa && child == 1) iscut[u] = 0;
    63         sc[u]++;
    64     }
    65     void Tarjan() {
    66         dfs_clock = 0;
    67         rep(i, 1, n)
    68             if (!pre[i])
    69                 dfs(i, i);
    70         rep(i, 1, n) 
    71             if (!iscut[i]) {
    72                 printf("%lld
    ", (n-1LL) << 1);
    73             }
    74             else printf("%lld
    ", (ans[i] + (n-sum[i]-1)*sum[i] + n-1) << 1);
    75     }
    76 } G;
    77 
    78 int n, m;
    79 
    80 int main() {
    81     n = read(), m = read(); G.init(n);
    82     rep(i, 1, m) {
    83         int u = read(), v = read();
    84         G.Add(u, v); G.Add(v, u);
    85     }
    86     G.Tarjan();
    87     return 0;
    88 }
  • 相关阅读:
    指向指针的指针
    判断是否遵守某个协议
    oc继承,实现,分类
    oc中没有空指针错误
    oc方法
    指针
    Array.diff
    ATM机允许4位或6位密码,而密码只能包含4位或6位数字。 如果函数传递了一个有效的PIN字符串,返回true,否则返回false。
    替换字符串中的字符为“(” 或“)”
    python 异常处理
  • 原文地址:https://www.cnblogs.com/ac-evil/p/10348432.html
Copyright © 2020-2023  润新知