P2542 [AHOI2005]航线规划

题目描述

对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的询问,输出一行一个整数表示关键航线数目。

说明

我们保证无论航线如何被破坏,任意时刻任意两个星球都能够相互到达。在整个数据中,任意两个星球之间最多只可能存在一条直接的航线。


思路:

有一个常见套路:对于删除一些边,采用离线逆序处理。

  1. 建要删去的边删去
  2. 对删去后的边进行缩点,得到一颗树
  3. 问题转化为求两点之间边数
  4. 逆序连边将处于环上的边权置0,采用树链剖分

细节:因为是点权下放至边权,所以每次不对LCA进行操作

PS:无向图建新图的一个错误我拍了2个小时mmp(居然还有60分)

错误的:

  1. void New()
  2. {
  3. for(int i=1;i<=n0;i++)
  4. for(int j=head0[i];j;j=next0[j])
  5. if(edge0[j]&&ha[i]!=ha[to0[j]])
  6. add(ha[i],ha[to0[j]]),add(ha[to0[j]],ha[i]);
  7. }

正确的:

  1. void New()
  2. {
  3. for(int i=1;i<=n0;i++)
  4. for(int j=head0[i];j;j=next0[j])
  5. if(edge0[j]&&ha[i]!=ha[to0[j]])
  6. add(ha[i],ha[to0[j]]);
  7. }

Code:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <map>
  4. #define mid (l+r>>1)
  5. #define Mid (L[id]+R[id]>>1)
  6. #define ls id<<1
  7. #define rs id<<1|1
  8. using namespace std;
  9. const int N=30010;
  10. const int M=100010;
  11. int head0[N],cnt0=0,to0[M<<1],next0[M<<1],edge0[M<<1];
  12. void add0(int u,int v,int w)
  13. {
  14. next0[++cnt0]=head0[u];edge0[cnt0]=w;to0[cnt0]=v;head0[u]=cnt0;
  15. }
  16. int head[N],cnt=0,to[M<<1],next[M<<1];
  17. void add(int u,int v)
  18. {
  19. next[++cnt]=head[u];to[cnt]=v;head[u]=cnt;
  20. }
  21. map <int,map <int,int > > del;//要删去的边
  22. int aska[N],askb[N],acnt=0,n0,m,n,ans[N],wcnt,typ[N];
  23. void Delete()
  24. {
  25. for(int i=1;i<=n0;i++)
  26. for(int j=head0[i];j;j=next0[j])
  27. if(del[i][to0[j]])
  28. edge0[j]=0;
  29. }
  30. int s[N],tot=0,time=0,low[N],dfn[N],in[N],ha[N];
  31. void tarjan(int now,int fa)
  32. {
  33. dfn[now]=low[now]=++time;
  34. s[++tot]=now,in[now]=1;
  35. for(int i=head0[now];i;i=next0[i])
  36. {
  37. if(!edge0[i]) continue;
  38. int v=to0[i];
  39. if(!dfn[v])
  40. {
  41. tarjan(v,now);
  42. low[now]=min(low[now],low[v]);
  43. }
  44. else if(in[v]&&v!=fa)
  45. low[now]=min(low[now],dfn[v]);
  46. }
  47. if(dfn[now]==low[now])
  48. {
  49. int tmp;
  50. n++;
  51. do
  52. {
  53. tmp=s[tot--];
  54. in[tmp]=0;
  55. ha[tmp]=n;
  56. }while(tmp!=now);
  57. }
  58. }
  59. void New()
  60. {
  61. for(int i=1;i<=n0;i++)
  62. for(int j=head0[i];j;j=next0[j])
  63. if(edge0[j]&&ha[i]!=ha[to0[j]])
  64. add(ha[i],ha[to0[j]]);
  65. }
  66. int top[N],f[N],ws[N],siz[N],dep[N];
  67. void dfs1(int now)
  68. {
  69. siz[now]++;
  70. for(int i=head[now];i;i=next[i])
  71. {
  72. int v=to[i];
  73. if(f[now]!=v)
  74. {
  75. f[v]=now;
  76. dep[v]=dep[now]+1;
  77. dfs1(v);
  78. siz[now]+=siz[v];
  79. if(siz[ws[now]]<siz[v])
  80. ws[now]=v;
  81. }
  82. }
  83. }
  84. void dfs2(int now,int anc)
  85. {
  86. dfn[now]=++time;
  87. top[now]=anc;
  88. if(!ws[now]) return;
  89. dfs2(ws[now],anc);
  90. for(int i=head[now];i;i=next[i])
  91. if(!dfn[to[i]])
  92. dfs2(to[i],to[i]);
  93. }
  94. int dat[N<<2],L[N<<2],R[N<<2];
  95. void build(int id,int l,int r)
  96. {
  97. dat[id]=(r+1-l);
  98. L[id]=l,R[id]=r;
  99. if(l==r) return;
  100. build(ls,l,mid);
  101. build(rs,mid+1,r);
  102. }
  103. void change(int id,int l,int r)
  104. {
  105. if(!dat[id]) return;
  106. if(L[id]==l&&R[id]==r)
  107. {
  108. dat[id]=0;
  109. return;
  110. }
  111. if(r<=Mid) change(ls,l,r);
  112. else if(l>Mid) change(rs,l,r);
  113. else change(ls,l,Mid),change(rs,Mid+1,r);
  114. dat[id]=dat[ls]+dat[rs];
  115. }
  116. int query(int id,int l,int r)
  117. {
  118. if(!dat[id]) return 0;
  119. if(L[id]==l&&R[id]==r)
  120. return dat[id];
  121. if(r<=Mid) return query(ls,l,r);
  122. else if(l>Mid) return query(rs,l,r);
  123. else return query(ls,l,Mid)+query(rs,Mid+1,r);
  124. }
  125. void t_change(int x,int y)
  126. {
  127. while(top[x]!=top[y])
  128. {
  129. if(dep[top[x]]>dep[top[y]])
  130. {
  131. change(1,dfn[top[x]],dfn[x]);
  132. x=f[top[x]];
  133. }
  134. else
  135. {
  136. change(1,dfn[top[y]],dfn[y]);
  137. y=f[top[y]];
  138. }
  139. }
  140. if(dfn[x]!=dfn[y])
  141. change(1,min(dfn[x],dfn[y])+1,max(dfn[x],dfn[y]));
  142. }
  143. int t_query(int x,int y)
  144. {
  145. int ans=0;
  146. while(top[x]!=top[y])
  147. {
  148. if(dep[top[x]]>dep[top[y]])
  149. {
  150. ans+=query(1,dfn[top[x]],dfn[x]);
  151. x=f[top[x]];
  152. }
  153. else
  154. {
  155. ans+=query(1,dfn[top[y]],dfn[y]);
  156. y=f[top[y]];
  157. }
  158. }
  159. if(dfn[x]!=dfn[y])
  160. ans+=query(1,min(dfn[x],dfn[y])+1,max(dfn[x],dfn[y]));
  161. return ans;
  162. }
  163. int cntt[N];
  164. int main()
  165. {
  166. scanf("%d%d",&n0,&m);
  167. int u,v;
  168. for(int i=1;i<=m;i++)
  169. {
  170. scanf("%d%d",&u,&v);
  171. add0(u,v,1),add0(v,u,1);
  172. }
  173. int a,b,c;
  174. scanf("%d%d%d",&c,&a,&b);
  175. while(2333)
  176. {
  177. aska[++acnt]=a,askb[acnt]=b,typ[acnt]=c;
  178. if(!c)
  179. del[a][b]=1,del[b][a]=1;
  180. scanf("%d",&c);
  181. if(c==-1)
  182. break;
  183. scanf("%d%d",&a,&b);
  184. }
  185. Delete();//删掉访问的边
  186. tarjan(1,0);//缩点
  187. New();//建立新图
  188. memset(dfn,0,sizeof(dfn));
  189. time=0;
  190. dfs1(1);
  191. dfs2(1,1);
  192. build(1,1,n);
  193. for(int i=acnt;i;i--)
  194. {
  195. if(typ[i]) ans[++wcnt]=t_query(ha[aska[i]],ha[askb[i]]);
  196. else t_change(ha[aska[i]],ha[askb[i]]);
  197. }
  198. for(int i=wcnt;i;i--)
  199. printf("%d\n",ans[i]);
  200. return 0;
  201. }

2018.6.24

洛谷 P2542 [AHOI2005]航线规划 解题报告的更多相关文章

  1. 洛谷P2542 [AHOI2005]航线规划(LCT,双连通分量,并查集)

    洛谷题目传送门 太弱了不会树剖,觉得LCT好写一些,就上LCT乱搞,当LCT维护双连通分量的练手题好了 正序删边是不好来维护连通性的,于是就像水管局长那样离线处理,逆序完成操作 显然,每个点可以代表一 ...

  2. 洛谷 P2542 [AHOI2005]航线规划(Link-cut-tree)

    题面 洛谷 bzoj 题解 离线处理+LCT 有点像星球大战 我们可以倒着做,断边变成连边 我们可以把边变成一个点 连边时,如果两个点本身不联通,就\(val\)赋为\(1\),并连接这条边 如果,两 ...

  3. 洛谷 P2542 [AHOI2005]航线规划 树链剖分_线段树_时光倒流_离线

    Code: #include <map> #include <cstdio> #include <algorithm> #include <cstring&g ...

  4. 洛谷_Cx的故事_解题报告_第四题70

    1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h>   struct node {     long x,y,c; ...

  5. 洛谷 P2317 [HNOI2005]星际贸易 解题报告

    P2317 [HNOI2005]星际贸易 题目描述 输入输出格式 输入格式: 输出格式: 如果可以找到这样的方案,那么输出文件output.txt中包含两个整数X和Y.X表示贸易额,Y表示净利润并且两 ...

  6. 洛谷 P3802 小魔女帕琪 解题报告

    P3802 小魔女帕琪 题目背景 从前有一个聪明的小魔女帕琪,兴趣是狩猎吸血鬼. 帕琪能熟练使用七种属性(金.木.水.火.土.日.月)的魔法,除了能使用这么多种属性魔法外,她还能将两种以上属性组合,从 ...

  7. 洛谷 P2606 [ZJOI2010]排列计数 解题报告

    P2606 [ZJOI2010]排列计数 题目描述 称一个\(1,2,...,N\)的排列\(P_1,P_2...,P_n\)是\(Magic\)的,当且仅当对所以的\(2<=i<=N\) ...

  8. 洛谷1303 A*B Problem 解题报告

    洛谷1303 A*B Problem 本题地址:http://www.luogu.org/problem/show?pid=1303 题目描述 求两数的积. 输入输出格式 输入格式: 两个数 输出格式 ...

  9. 洛谷 P3705 [SDOI2017]新生舞会 解题报告

    P3705 [SDOI2017]新生舞会 题目描述 学校组织了一次新生舞会,\(Cathy\)作为经验丰富的老学姐,负责为同学们安排舞伴. 有\(n\)个男生和\(n\)个女生参加舞会买一个男生和一个 ...

随机推荐

  1. 20155232《网络对抗》Exp5 MSF基础应用

    20155232<网络对抗>Exp5 MSF基础应用 基础问题回答 用自己的话解释什么是exploit,payload,encode. exploit:就是利用可能存在的漏洞对目标进行攻击 ...

  2. 20155320 Exp3 免杀原理与实践

    20155320 Exp3 免杀原理与实践 免杀 一般是对恶意软件做处理,让它不被杀毒软件所检测.也是渗透测试中需要使用到的技术. [基础问题回答] (1)杀软是如何检测出恶意代码的? 1.通过行为检 ...

  3. 20155327 实验四 Android程序设计

    20155327 实验四 Android程序设计 任务一: 完成Hello World, 要求修改res目录中的内容,Hello World后要显示自己的学号 步骤: 将布局文件activity_ma ...

  4. C++之enum枚举量声明、定义、使用与枚举类详解

    C++之enum枚举量声明.定义.使用与枚举类详解 学习一个东西,首先应该指导它能做什么,其次去知道它怎么去做,最后知道为什么去这么做. 知其然知其所以然.不能冒进 ,一步一步的慢慢来.

  5. WPF编程,C#中对话框自动关闭的一种方法。

    原文:WPF编程,C#中对话框自动关闭的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/details/8 ...

  6. mfc CProgressCtrl

    CProgressCtrl常用属性 CProgressCtrl类常用成员函数 CProgressCtrl代码示例 一.CProgressCtrl控件属性 当我们在处理大程序时,常常需要耗很长时间(比如 ...

  7. bootstrap-validator基本使用(自定义验证身份证号和手机号)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  8. 如何解决markdown中图片上传的问题

    1.第一种方式(图床) 1.1 google中的插件-新浪微博图床 2.第二种方式,操作流程如下 2.1 下载一个有道云笔记客户端 2.2 然后把图片通过有道云笔记分享出来,见下动态图 3.总结一下 ...

  9. Category Theory: 01 One Structured Family of Structures

    Category Theory: 01 One Structured Family of Structures 这次看来要放弃了.看了大概三分之一.似乎不能够让注意力集中了.先更新吧. 群的定义 \( ...

  10. Google Kickstart Round.B C. Diverse Subarray

    这题又是万恶的线段树 maxx[j]存储的是 l = xxx, r = j的时候的答案 我们会让 l 从 1到n 的遍历中,查询线段树的[l, n]中最大的答案 因为query的下界是n,所以单次查询 ...