zoukankan      html  css  js  c++  java
  • [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 }
  • 相关阅读:
    使用apache的ab命令进行压测
    mysql插入数据时,去掉重复的数据;
    CI框架的事务开启、提交和回滚
    电脑如何自动玩popstar
    Outsider(HNOI2019)
    洛谷P4689 [Ynoi2016]这是我自己的发明(莫队,树的dfn序,map,容斥原理)
    Ubuntu下编写终端界面交互式C++小程序的一些Trick(小技巧,gnome-terminal)
    贪心相关/模拟网络流、费用流细节梳理/模板(贪心,模拟费用流,栈)
    洛谷P3602 Koishi Loves Segments(贪心,multiset)
    洛谷CF809C Find a car(数位DP)
  • 原文地址:https://www.cnblogs.com/ac-evil/p/10348432.html
Copyright © 2011-2022 走看看