题目描述

对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系。 星际空间站的Samuel II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些星球从1开始编号1、2、3……。 一些先遣飞船已经出发,在星球之间开辟探险航线。 探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星球也可以使用这条航线。 例如下图所示:

在5个星球之间,有5条探险航线。 A、B两星球之间,如果某条航线不存在,就无法从A星球抵达B星球,我们则称这条航线为关键航线。 显然上图中,1号与5号星球之间的关键航线有1条:即为4-5航线。 然而,在宇宙中一些未知的磁暴和行星的冲撞,使得已有的某些航线被破坏,随着越来越多的航线被破坏,探险飞船又不能及时回复这些航线,可见两个星球之间的关键航线会越来越多。 假设在上图中,航线4-2(从4号星球到2号星球)被破坏。此时,1号与5号星球之间的关键航线就有3条:1-3,3-4,4-5。 小联的任务是,不断关注航线被破坏的情况,并随时给出两个星球之间的关键航线数目。现在请你帮助完成。

输入

第一行有两个整数N,M。表示有N个星球(1< N < 30000),初始时已经有M条航线(1 < M < 100000)。随后有M行,每行有两个不相同的整数A、B表示在星球A与B之间存在一条航线。接下来每行有三个整数C、A、B。C为1表示询问当前星球A和星球B之间有多少条关键航线;C为0表示在星球A和星球B之间的航线被破坏,当后面再遇到C为1的情况时,表示询问航线被破坏后,关键路径的情况,且航线破坏后不可恢复; C为-1表示输入文件结束,这时该行没有A,B的值。被破坏的航线数目与询问的次数总和不超过40000。

输出

对每个C为1的询问,输出一行一个整数表示关键航线数目。 注意:我们保证无论航线如何被破坏,任意时刻任意两个星球都能够相互到达。在整个数据中,任意两个星球之间最多只可能存在一条直接的航线。

样例输入

5 5
1 2
1 3
3 4
4 5
4 2
1 1 5
0 4 2
1 5 1
-1

样例输出

1
3


题解

树链剖分+线段树

由于没有加边操作,且保证图连通,所以我们可以离线处理,将删边转化为加边。

删除所有边以后剩下的是一个连通图,我们求出它的一棵生成树(这里求了DFS树),那么加入一条边就相当于两点之间路径上所有的边不再为关键航线。

然后按照逆时间顺序,将删除的边加上,处理询问。(需要把原来连通图中费树边也加上)

于是问题转化为:将两点间的所有边染色、询问两点间多少条边没有被染色。使用树链剖分+线段树水过即可。

  1. #include <map>
  2. #include <cstdio>
  3. #include <algorithm>
  4. #define N 30010
  5. #define lson l , mid , x << 1
  6. #define rson mid + 1 , r , x << 1 | 1
  7. using namespace std;
  8. struct data
  9. {
  10. int x , y , t;
  11. bool operator<(const data a)const {return t < a.t;}
  12. }a[N << 2];
  13. map<pair<int , int> , int> p;
  14. int qx[N << 2] , qy[N << 2] , qt[N << 2] , qa[N << 2] , q;
  15. int head[N] , to[N << 3] , next[N << 3] , cnt , fa[N] , deep[N] , si[N] , bl[N] , pos[N] , tot;
  16. int n , sum[N << 2] , tag[N << 2];
  17. void add(int x , int y)
  18. {
  19. to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
  20. }
  21. void dfs1(int x)
  22. {
  23. int i;
  24. si[x] = 1;
  25. for(i = head[x] ; i ; i = next[i])
  26. if(!si[to[i]])
  27. fa[to[i]] = x , deep[to[i]] = deep[x] + 1 , dfs1(to[i]) , si[x] += si[to[i]];
  28. }
  29. void dfs2(int x , int c)
  30. {
  31. int i , k = 0;
  32. bl[x] = c , pos[x] = ++tot;
  33. for(i = head[x] ; i ; i = next[i])
  34. if(fa[to[i]] == x && si[to[i]] > si[k])
  35. k = to[i];
  36. if(k)
  37. {
  38. dfs2(k , c);
  39. for(i = head[x] ; i ; i = next[i])
  40. if(fa[to[i]] == x && to[i] != k)
  41. dfs2(to[i] , to[i]);
  42. }
  43. }
  44. void pushup(int x)
  45. {
  46. sum[x] = sum[x << 1] + sum[x << 1 | 1];
  47. }
  48. void pushdown(int x)
  49. {
  50. if(tag[x]) tag[x] = sum[x << 1] = sum[x << 1 | 1] = 0 , tag[x << 1] = tag[x << 1 | 1] = 1;
  51. }
  52. void build(int l , int r , int x)
  53. {
  54. if(l == r)
  55. {
  56. sum[x] = 1;
  57. return;
  58. }
  59. int mid = (l + r) >> 1;
  60. build(lson) , build(rson);
  61. pushup(x);
  62. }
  63. void update(int b , int e , int l , int r , int x)
  64. {
  65. if(b <= l && r <= e)
  66. {
  67. sum[x] = 0 , tag[x] = 1;
  68. return;
  69. }
  70. pushdown(x);
  71. int mid = (l + r) >> 1;
  72. if(b <= mid) update(b , e , lson);
  73. if(e > mid) update(b , e , rson);
  74. pushup(x);
  75. }
  76. int query(int b , int e , int l , int r , int x)
  77. {
  78. if(b <= l && r <= e) return sum[x];
  79. pushdown(x);
  80. int mid = (l + r) >> 1 , ans = 0;
  81. if(b <= mid) ans += query(b , e , lson);
  82. if(e > mid) ans += query(b , e , rson);
  83. return ans;
  84. }
  85. void modify(int x , int y)
  86. {
  87. while(bl[x] != bl[y])
  88. {
  89. if(deep[bl[x]] < deep[bl[y]]) swap(x , y);
  90. update(pos[bl[x]] , pos[x] , 1 , n , 1) , x = fa[bl[x]];
  91. }
  92. if(deep[x] > deep[y]) swap(x , y);
  93. if(deep[x] != deep[y]) update(pos[x] + 1 , pos[y] , 1 , n , 1);
  94. }
  95. int solve(int x , int y)
  96. {
  97. int ans = 0;
  98. while(bl[x] != bl[y])
  99. {
  100. if(deep[bl[x]] < deep[bl[y]]) swap(x , y);
  101. ans += query(pos[bl[x]] , pos[x] , 1 , n , 1) , x = fa[bl[x]];
  102. }
  103. if(deep[x] > deep[y]) swap(x , y);
  104. if(deep[x] != deep[y]) ans += query(pos[x] + 1 , pos[y] , 1 , n , 1);
  105. return ans;
  106. }
  107. void dfs3(int x)
  108. {
  109. int i;
  110. for(i = head[x] ; i ; i = next[i])
  111. {
  112. if(fa[to[i]] == x) dfs3(to[i]);
  113. else if(fa[x] != to[i] && deep[to[i]] > deep[x]) modify(x , to[i]);
  114. }
  115. }
  116. int main()
  117. {
  118. int m , i , c , now = 0 , u , v , h;
  119. scanf("%d%d" , &n , &m);
  120. for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &a[i].x , &a[i].y) , p[make_pair(a[i].x , a[i].y)] = i;
  121. while(~scanf("%d" , &c) && ~c)
  122. {
  123. now ++ ;
  124. if(c) q ++ , scanf("%d%d" , &qx[q] , &qy[q]) , qt[q] = now;
  125. else scanf("%d%d" , &u , &v) , a[p[make_pair(u , v)]].t = now;
  126. }
  127. sort(a + 1 , a + m + 1);
  128. for(i = 1 ; i <= m ; i ++ )
  129. if(!a[i].t)
  130. add(a[i].x , a[i].y) , add(a[i].y , a[i].x);
  131. dfs1(1) , dfs2(1 , 1) , build(1 , n , 1) , dfs3(1);
  132. for(i = q , h = m ; i ; i -- )
  133. {
  134. while(a[h].t > qt[i]) modify(a[h].x , a[h].y) , h -- ;
  135. qa[i] = solve(qx[i] , qy[i]);
  136. }
  137. for(i = 1 ; i <= q ; i ++ ) printf("%d\n" , qa[i]);
  138. return 0;
  139. }

【bzoj1959】[Ahoi2005]LANE 航线规划 树链剖分+线段树的更多相关文章

  1. 【bzoj2402】陶陶的难题II 分数规划+树链剖分+线段树+STL-vector+凸包+二分

    题目描述 输入 第一行包含一个正整数N,表示树中结点的个数.第二行包含N个正实数,第i个数表示xi (1<=xi<=10^5).第三行包含N个正实数,第i个数表示yi (1<=yi& ...

  2. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  3. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  4. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  5. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  6. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  7. bzoj4034 (树链剖分+线段树)

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

  8. HDU4897 (树链剖分+线段树)

    Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...

  9. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

随机推荐

  1. UVA 1623 Enther the Dragon 神龙喝水 (贪心)

    贪心,每次遇到一个满水的湖要下暴雨的时候,就往前找之前最后一次满水之后的第一个没有下雨的且没有被用掉天day1. 因为如果不选这day1,那么之后的湖不一定能选上这一天.如果这一天后面还有没有下雨的天 ...

  2. Android(java)学习笔记131:关于构造代码块,构造函数的一道面试题(华为面试题)

    1. 代码实例: package text; public class TestStaticCon { public static int a = 0; static { a = 10; System ...

  3. coredata 删除与更新

    http://blog.csdn.net/rhljiayou/article/details/18037729 //删除 -(void)deleteData { NSManagedObjectCont ...

  4. DROP OPERATOR - 删除一个操作符

    SYNOPSIS DROP OPERATOR name ( lefttype | NONE , righttype | NONE ) [ CASCADE | RESTRICT ] DESCRIPTIO ...

  5. Python01 VSCode开发环境和入门程序

    1.Python的下载和安装 最新版本python3.7.3 https://www.python.org/downloads/release/python-373/ web-based: 在线安装包 ...

  6. Ab initio methods|Evidence-based methods|maximum-likelihood|branch-site|H1|H0|GO|dS/dN ratio

    (Gene prediction and comparison) 使用基于基因组序列的从头预测方法(Ab initio methods)(同时分别使用头预测软件( GENSCAN和 AUGUSTUS) ...

  7. OC和C++的混用2

    苹果的Objective-C编译器允许用户在同一个源文件里自由地混合使用C++和Objective-C,混编后的语言叫Objective-C++.有了它,你就可以在Objective-C应用程序中使用 ...

  8. 浅探webpack优化

    由于前端的快速发展,相关工具的发展速度也是相当迅猛,各大框架例如vue,react都有自己优秀的脚手架工具来帮助我们快速启动一个新项目,也正式因为这个原因,我们对于脚手架中最关键的一环webpack相 ...

  9. Verilog之语句位置

    1.if语句.case语句必须放在always过程语句块中. 2.verilog的系统函数比如:\(display/\)monitor必须放在initial 过程语句块中.这点尚为理解为何,但必须这样 ...

  10. Letters CodeForces - 978C (二分)

    Time limit4000 ms Memory limit262144 kB There are nn dormitories in Berland State University, they a ...