一道有点神的线段树。

Description

  有一天,由于某种穿越现象作用,你来到了传说中的小人国。小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个城市和3C-2条道路。 小人国的交通状况非常槽糕。有的时候由于交通堵塞,两座城市之间的道路会变得不连通,直到拥堵解决,道路才会恢复畅通。初来乍到的你决心毛遂自荐到交通部某份差事,部长听说你来自一个科技高度发达的世界,喜出望外地要求你编写一个查询应答系统,以挽救已经病入膏肓的小人国交通系统。 小人国的交通部将提供一些交通信息给你,你的任务是根据当前的交通情况回答查询的问题。交通信息可以分为以下几种格式:
  Close r1 c1 r2 c2:相邻的两座城市(r1,c1)和(r2,c2)之间的道路被堵塞了;
  Open r1 c1 r2 c2:相邻的两座城市(r1,c1)和(r2,c2)之间的道路被疏通了;
  Ask r1 c1 r2 c2:询问城市(r1,c1)和(r2,c2)是否连通。如果存在一条路径使得这两条城市连通,则返回Y,否则返回N。

Input

  第一行只有一个整数C,表示网格的列数。接下来若干行,每行为一条交通信息,以单独的一行“Exit”作为结束。我们假设在一开始所有的道路都是堵塞的。

Output

  对于每个查询,输出一个“Y”或“N”。

Sample Input

  2
  Open 1 1 1 2
  Open 1 2 2 2
  Ask 1 1 2 2
  Ask 2 1 2 2
  Exit

Sample Output

  Y
  N

HINT

  C,信息条数<=100000。

Solution

  修改、询问……首先确定这是一道数据结构题。

  可是它每次询问的是两个点的连通性,可持久化并查集?你在逗我?

  连通性怎么维护?

  我们发现它实质上是在一条线段上进行连通性维护的,即使它有两条,实际上是没有太大区别的。

  我们仔细思考一下行数只有1的时候,用数据结构怎么做:

  用线段树维护只在该区间影响下,区间两端是否连通,合并起来是毫无压力的。

  那么行数为2的时候,我们也试试看这样维护?

  我们用线段树维护只在该区间影响下,区间中左上和右上右下,左下和右上右下是否连通,合并起来同样也是没有压力的。

  这样我们似乎就解决了询问的问题?

  显然这只是其中一种情况,但是还可能有区间外的边影响其连通性的情况:

    

    

  当然还有更骚的,可以这样:

    

  其实不外乎就是这4种情况,幸好我们都是可以处理的。

  你会发现后3种情况我们可以是看作几个区间的共同作用:

    

    

  这样你就突然发现,每个区间的作用是独立的,也就是说正好是我们所能够维护的。

  所以除了上面4项需要维护,我们还需要维护区间左上和左下是否连通,右上和右下是否连通,合并同样很好实现。

  这样我们就完美解决了询问操作。

  至于修改操作根本就是小case了,小C也大约说一下自己的做法。

  更改不同行之间的连通性就是直接改。

  然而更改不同列之间的连通性可以动动脑子,我们可以预处理出第i列到第i+1列之间的道路哪个区间更新时会用到它。

  例如n=8,第4、5列之间的道路在[1,8]区间更新时被用到;第1、2列之间的道路在[1,2]区间更新时被用到。

  很容易证明列间道路和它的更新区间是一一对应的关系。

  所以修改某条列间道路时,只要顺着线段树往下找它对应的更新区间,做一次更新操作,再向上更新即可。

  时间复杂度O(nlogn*更新常数)。(不知道出题人总时间开3s是什么心态……)

  (合并操作写得像豆腐块一样)

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #define MN 100005
  5. #define l(a) (a<<1)
  6. #define r(a) (a<<1|1)
  7. using namespace std;
  8. const int zx[][]={{,},{,}};
  9. int lk[][MN];
  10. struct node
  11. {
  12. int r; bool a[]; //--\/||
  13. friend node operator+(const node& a,const node& b)
  14. {
  15. node c;
  16. c.r=b.r;
  17. c.a[]=a.a[]&&lk[][a.r]&&b.a[]||a.a[]&&lk[][a.r]&&b.a[];
  18. c.a[]=a.a[]&&lk[][a.r]&&b.a[]||a.a[]&&lk[][a.r]&&b.a[];
  19. c.a[]=a.a[]&&lk[][a.r]&&b.a[]||a.a[]&&lk[][a.r]&&b.a[];
  20. c.a[]=a.a[]&&lk[][a.r]&&b.a[]||a.a[]&&lk[][a.r]&&b.a[];
  21. c.a[]=a.a[]||a.a[]&&a.a[]&&lk[][a.r]&&lk[][a.r]&&b.a[];
  22. c.a[]=b.a[]||b.a[]&&b.a[]&&lk[][a.r]&&lk[][a.r]&&a.a[];
  23. return c;
  24. }
  25. }t[MN<<];
  26. int ct[MN][];
  27. int n;
  28.  
  29. inline int read()
  30. {
  31. int n=,f=; char c=getchar();
  32. while (c<'' || c>'') {if(c=='-')f=-; c=getchar();}
  33. while (c>='' && c<='') {n=n*+c-''; c=getchar();}
  34. return n*f;
  35. }
  36.  
  37. node getitv(int x,int L,int R,int ql,int qr)
  38. {
  39. if (ql==L&&qr==R) return t[x];
  40. int mid=L+R>>;
  41. if (qr<=mid) return getitv(l(x),L,mid,ql,qr);
  42. else if (ql>mid) return getitv(r(x),mid+,R,ql,qr);
  43. else return getitv(l(x),L,mid,ql,mid)+getitv(r(x),mid+,R,mid+,qr);
  44. }
  45. void getcg2(int x,int L,int R,int ql,int qr)
  46. {
  47. if (ql==L&&qr==R) {t[x]=t[l(x)]+t[r(x)]; return;}
  48. int mid=L+R>>;
  49. if (qr<=mid) getcg2(l(x),L,mid,ql,qr);
  50. else if (ql>mid) getcg2(r(x),mid+,R,ql,qr);
  51. t[x]=t[l(x)]+t[r(x)];
  52. }
  53. void getcg1(int x,int L,int R,int q)
  54. {
  55. if (L==R) {t[x].a[]^=; t[x].a[]^=; t[x].a[]^=; t[x].a[]^=; return;}
  56. int mid=L+R>>;
  57. if (q<=mid) getcg1(l(x),L,mid,q); else getcg1(r(x),mid+,R,q);
  58. t[x]=t[l(x)]+t[r(x)];
  59. }
  60.  
  61. void build(int x,int L,int R)
  62. {
  63. if (L==R) {t[x].r=R; t[x].a[]=t[x].a[]=true; return;}
  64. int mid=L+R>>;
  65. ct[mid][]=L; ct[mid][]=R;
  66. build(l(x),L,mid); build(r(x),mid+,R);
  67. t[x]=t[l(x)]+t[r(x)];
  68. }
  69.  
  70. int main()
  71. {
  72. register int x1,y1,x2,y2,g;
  73. char c[];
  74. n=read();
  75. build(,,n);
  76. for (scanf("%s",c);c[]!='E';scanf("%s",c))
  77. {
  78. x1=read()-; y1=read(); x2=read()-; y2=read();
  79. if (c[]=='O'||c[]=='C')
  80. {
  81. if (x1==x2) {g=x1; if (y1>y2) swap(y1,y2);} else g=;
  82. if (lk[g][y1]^(c[]=='C')) continue;
  83. lk[g][y1]^=;
  84. if (g==) getcg1(,,n,y1); else getcg2(,,n,ct[y1][],ct[y1][]);
  85. }
  86. else if (c[]=='A')
  87. {
  88. if (y1>y2) swap(x1,x2),swap(y1,y2);
  89. node lt=getitv(,,n,y1,y2),lt1,lt2;
  90. if (lt.a[zx[x1][x2]]) {puts("Y"); continue;}
  91. if (y1>) lt1=getitv(,,n,,y1-);
  92. if (y2<n) lt2=getitv(,,n,y2+,n);
  93. if (y1>&&lt.a[zx[!x1][x2]]) if (lk[][y1-]&&lk[][y1-]&&lt1.a[]) {puts("Y"); continue;}
  94. if (y2<n&&lt.a[zx[x1][!x2]]) if (lk[][y2 ]&&lk[][y2 ]&&lt2.a[]) {puts("Y"); continue;}
  95. if (y1>&&y2<n&&lt.a[zx[!x1][!x2]])
  96. if (lk[][y1-]&&lk[][y1-]&&lt1.a[]&&lk[][y2 ]&&lk[][y2 ]&&lt2.a[]) {puts("Y"); continue;}
  97. puts("N");
  98. }
  99. }
  100. }

Last Word

  小D当时就丢了一句“大力维护就好了啊”让小C茅塞顿开……

  “初来乍到”、“毛遂自荐”、“喜出望外”、“病入膏肓”……出题人的语文水平还是值得肯定的。

[BZOJ]1018 堵塞的交通(SHOI2008)的更多相关文章

  1. BZOJ 1018 堵塞的交通

    Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一 ...

  2. BZOJ 1018 堵塞的交通traffic(线段树)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1018 题意:一个2*n的格子,相邻格子之间有一条道路.初始时道路是不通的. 三种操作:( ...

  3. 【BZOJ】【1018】【SHOI2008】堵塞的交通traffic

    线段树 这题的线段树+分类讨论蛮神奇的……我以前学的线段树简直就是渣渣QAQ 看了下ydc题解里的思想>_>用线段树维护连通性!那么就自己写吧……每个节点表示一段区间的连通性(我的叶子节点 ...

  4. 数据结构(线段树):BZOJ 1018: [SHOI2008]堵塞的交通traffic

    1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 2638  Solved: 864 Descri ...

  5. BZOJ 1018 [SHOI2008]堵塞的交通traffic

    1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 2247  Solved: 706[Submit ...

  6. BZOJ 1018: [SHOI2008]堵塞的交通traffic [线段树 区间信息]

    1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 3064  Solved: 1027[Submi ...

  7. [BZOJ 1018] [SHOI2008] 堵塞的交通traffic 【线段树维护联通性】

    题目链接:BZOJ - 1018 题目分析 这道题就说明了刷题少,比赛就容易跪..SDOI Round1 Day2 T3 就是与这道题类似的..然而我并没有做过这道题.. 这道题是线段树维护联通性的经 ...

  8. bzoj千题计划108:bzoj1018: [SHOI2008]堵塞的交通traffic

    http://www.lydsy.com/JudgeOnline/problem.php?id=1018 关键点在于只有两行 所以一个2*m矩形连通情况只有6种 编号即对应代码中的a数组 线段树维护 ...

  9. 1018: [SHOI2008]堵塞的交通traffic

    1018: [SHOI2008]堵塞的交通traffic 链接 分析: 用线段树维护区间的四个端点的联通情况,然后查询的时候,把所有覆盖到的区间合并起来即可. 六种情况左上到右上(左边到右边的情况)… ...

随机推荐

  1. 详谈C++虚函数表那回事(多重继承关系)

    上一篇说了一般继承,也就是单继承的虚函数表,接下来说说多重继承的虚函数表: 1.无虚函数覆盖的多重继承: 代码: #pragma once //无覆盖,多重继承 class Base1 { publi ...

  2. css中的position

    一.position语法与结构 position语法: position : static absolute relative position参数:static : 无特殊定位,对象遵循HTML定位 ...

  3. [笔试题目]使用Stringbuffer无 参的构造函数创建 一个对象时,默认的初始容量是多少? 如果长度不够使用了,自动增长多少倍?

    [笔试题目] 使用Stringbuffer无 参的构造函数创建 一个对象时,默认的初始容量是多少? 如果长度不够使用了,自动增长多少倍? StringBuffer 底层是依赖了一个字符数组才能存储字符 ...

  4. eclipse maven项目目录

    今天遇见一个错误,关于eclipse项目的路径问题,web-inf的路径,上图和下图出现了两种web-INF,src的web-INFf和webContent的web-INF,src里面的文件需要编译以 ...

  5. PHP冒泡排序、选择排序、插入排序

    $arr = [1, 8, 7, 5, 4, 2, 11, 9, 20]; 冒泡排序: for ($i = 0; $i < count($arr); $i ++) { for ($j = 0; ...

  6. Web Api 过滤器之 AuthorizationFilter 验证过滤器

    该过滤器是最先执行的过滤器,即使把它放在最后 API [MyActionFilter] [MyExceptionFilter] [MyAuthorize] public void Get() { Tr ...

  7. 增加Linux虚拟机的硬盘空间

    原配置为40G,现需要增加到60G,操作方法如下: 一.虚拟机关机,在编辑设置里调整硬盘空间到60G 二.虚拟机开机,扩展硬盘空间 1.安装gparted,命令如下 sudo apt-get inst ...

  8. C语言学习(一)

    C语言易学难精,如果在平时的编程中,加入一些小技巧,可以提供程序运行的效率,何乐而不为呢? 本小白初学C语言准备记录自己的学C之路,经常贴一些自己觉得优化的小程序代码,希望大神们不吝 赐教. 宏定义下 ...

  9. ELK学习总结(1-1)ELK是什么

    1.elk 是什么 ? Elastic Stack(旧称ELK Stack),是一种能够从任意数据源抽取数据,并实时对数据进行搜索.分析和可视化展现的数据分析框架.(hadoop同一个开发人员) ja ...

  10. 访问远程的docker

        docker version vim /etc/default/docker DOCKER_OPTS="  -Label name=dockerserver2" docke ...