zoukankan      html  css  js  c++  java
  • Hdu 5458 Stability (LCA + 并查集 + 树状数组 + 缩点)

    题目链接:

      Hdu 5458 Stability

    题目描述:

      给出一个还有环和重边的图G,对图G有两种操作:

      1 u v, 删除u与v之间的一天边 (保证这个边一定存在)

      2 u v, 查询u到v的路径上有几条桥。

    解题思路:

      这个题目有很多次操作,包含查询和删边两类,首先想到的是连通分量加缩点。如果按照顺序来,删边时候求桥就是问题了。所以可以离线处理,然后一边记录答案一边加边缩点。

      对于一个图,把连通分量缩成一个点后,这个图就成为了一棵树, 然后深度差就等于桥的数目。查询的时候对于(u, v)桥的数目等于(设定deep[x]为x的深度,LCA(x, y)为(x, y)的父节点) deep[u] + deep[v] - 2 * deep[LCA(u, v)];

      现在问题就成了怎么才能更快的缩点和维护点的深度。

      缩点问题:在树上加上一条边就会形成一个环,然后这个环(强连通分量)上点就会被缩成一个点,然后用并查集来维护强联通分量,每次只需要合并父节点(每个点只能被缩一次,复杂度被平摊还是很可观的)

      维护节点深度:每次儿子节点合并到父亲节点的时候,儿子节点的子孙节点的深度都要减一。在这里我们可以用dfs序 + 树状数组来维护节点的深度。利用树状数组的区间更改点查询优化维护深度的操作。

      还有最后一个问题就是计算(u, v)节点之间桥数目的时候,需要用到LCA,可以利用树上倍增LCA来优化时间复杂度。

    这个题目还是很值得本扎扎练手的,考察了很多东西,真是把压箱底的东西都翻出来晒了晒,仰慕当场ac的聚聚们。

      1 #include <vector>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <iostream>
      5 #include <algorithm>
      6 using namespace std;
      7 const int maxn = 30010;
      8 const int N = 100010;
      9 const int M = 16;
     10 
     11 struct node
     12 {
     13     int to, del;
     14     node(int x):to(x),del(0) {}
     15     bool operator < (const node & a) const
     16     {
     17         if (to != a.to) return to < a.to;
     18         return del > a.del;
     19     }
     20 };
     21 vector <node> vec[maxn];
     22 
     23 struct Query
     24 {
     25     int op, u, v;
     26     void read ()
     27     {
     28         scanf ("%d %d %d", &op, &u, &v);
     29         if (op == 1)
     30         {
     31             lower_bound (vec[u].begin(), vec[u].end(), node(v)) -> del = true;
     32             lower_bound (vec[v].begin(), vec[v].end(), node(u)) -> del = true;
     33         }
     34     }
     35 } query[N];
     36 
     37 int n, m, q;
     38 
     39 void init ()
     40 {
     41     for (int i=0; i<=n; i++)
     42         vec[i].clear();
     43 }
     44 
     45 struct bit_tree
     46 {
     47     int tree[maxn];
     48     
     49     void init()
     50     {
     51         memset (tree, 0, sizeof(tree));
     52     }
     53     
     54     int lowbit (int x)
     55     {
     56         return x & (-x);
     57     }
     58     
     59     void change (int x, int num)
     60     {
     61         while (x <= n)
     62         {
     63             tree[x] += num;
     64             x += lowbit (x);
     65         }
     66     }
     67     
     68     void update (int x, int y, int num)
     69     {
     70         change (x, num);
     71         change (y+1, -num);
     72     }
     73     
     74     int query (int x)
     75     {
     76         int res = 0;
     77         while (x)
     78         {
     79             res += tree[x];
     80             x -= lowbit (x);
     81         }
     82         return res;
     83     }
     84     
     85 }Bit_tree;
     86 
     87 int begin_id[maxn], end_id[maxn], deep[maxn], ntime;
     88 int fa[maxn][M];
     89 void dfs (int u, int father, int dep)
     90 {
     91     if (father > 0)
     92         vec[u].erase (lower_bound(vec[u].begin(), vec[u].end(), node(father)));
     93         
     94     fa[u][0] = father;
     95     begin_id[u] = ++ntime;
     96     deep[u] = dep;
     97     
     98     for (int i=0; i<vec[u].size(); i++)
     99     {
    100         node p = vec[u][i];
    101         if (p.del || begin_id[p.to]) continue;
    102         vec[u][i].del = true;
    103         dfs (p.to, u, dep+1);
    104     }
    105     
    106     end_id[u] = ntime;
    107     Bit_tree.update (begin_id[u], end_id[u], 1);
    108 }
    109 
    110 struct Lca
    111 {
    112     void init ()
    113     {
    114         for (int i=1; i<M; i++)
    115             for (int j=1; j<=n; j++)
    116                 fa[j][i] = fa[fa[j][i-1]][i-1];
    117     }
    118     
    119     int lca (int u, int v)
    120     {
    121         if (deep[u] < deep[v])   swap (u, v);
    122         int num = deep[u] - deep[v];
    123         for (int i=0; i<M; i++)
    124             if ((1<<i) & num)   u = fa[u][i];
    125         if (u == v) return u;
    126         for (int i=M-1; i>=0; i--)
    127             if (fa[u][i] != fa[v][i])
    128             {
    129                 u = fa[u][i];
    130                 v = fa[v][i];
    131             }
    132         return fa[u][0];
    133     }
    134     
    135 }LCA;
    136 
    137 int father[maxn];
    138 struct UNion
    139 {
    140     void init()
    141     {
    142         for (int i=0; i<=n; i++)
    143             father[i] = i;
    144     }
    145     
    146     int find (int x)
    147     {
    148         if (x != father[x]) father[x] = find (father[x]);
    149         return father[x];
    150     }
    151     
    152     void merge_fa (int x, int y)
    153     {
    154         x = find (x);
    155         while (x != y)
    156         {
    157             int t = find(fa[x][0]);
    158             father[x] = t;
    159             Bit_tree.update(begin_id[x], end_id[x], -1);
    160             x = t;
    161         }
    162     }
    163     
    164     void merge (int x, int y)
    165     {
    166         int l = find (LCA.lca (x, y));
    167         merge_fa (x, l);
    168         merge_fa (y, l);
    169     }
    170     
    171 }Union;
    172 
    173 int ans[N], res;
    174 void solve ()
    175 {
    176     Bit_tree.init ();
    177     ntime = res = 0;
    178     memset (begin_id, 0, sizeof(begin_id));
    179     dfs (1, 0, 1);
    180     LCA.init ();
    181     Union.init();
    182     
    183     for (int i=1; i<=n; i++)
    184     {
    185         for (int j=0; j<vec[i].size(); j++)
    186         {
    187             node p = vec[i][j];
    188             if (p.del)  continue;
    189             Union.merge (p.to, i);
    190         }
    191     }
    192 
    193     for (int i=q; i>0; i--)
    194     {
    195         Query p = query[i];
    196         int u = begin_id[p.u];
    197         int v = begin_id[p.v];
    198         int x = begin_id[LCA.lca(p.u, p.v)];
    199         if (p.op == 1)
    200             Union.merge(p.u, p.v);
    201         else
    202             ans[++ res] = Bit_tree.query(u) + Bit_tree.query(v) - 2*Bit_tree.query(x);
    203     }
    204     
    205     while(res)
    206         printf ("%d
    ", ans[res --]);
    207 }
    208 
    209 int main ()
    210 {
    211     int t, u, v;
    212     scanf ("%d", &t);
    213     
    214     for (int i=1; i<=t; i++)
    215     {
    216         scanf("%d %d %d", &n, &m, &q);
    217         init ();
    218         
    219         for (int j=0; j<m; j++)
    220         {
    221             scanf ("%d %d", &u, &v);
    222             vec[u].push_back (node(v));
    223             vec[v].push_back (node(u));
    224         }
    225         
    226         for (int j=1; j<=n; j++)
    227             sort (vec[j].begin(), vec[j].end());
    228             
    229         for (int j=1; j<=q; j++)
    230             query[j].read();
    231             
    232         printf ("Case #%d:
    ", i);
    233         solve ();
    234         
    235     }
    236     return 0;
    237 }

      

    本文为博主原创文章,未经博主允许不得转载。
  • 相关阅读:
    jstl <c:url>标签
    4.12快速分类
    2.递归回溯求子集和数问题
    计算圆面积
    openal在vs2010中的配置
    结构体数组排序
    检测信号的有无
    matlab中mat文件简单存/取
    m文件转换c代码
    安装fftw到window(vs2010)及使用fftw库函数实现4096点fft变换计算
  • 原文地址:https://www.cnblogs.com/alihenaixiao/p/4845733.html
Copyright © 2011-2022 走看看