这题需要维护连通性,看到有连接删除,很容易直接就想LCT了。然而这题点数20w操作10w,LCT卡常估计过不去。看到这个东西只有两行,考虑能否用魔改后的线性数据结构去维护。我想到了线段树。

考虑如果两个点相连,能有几种情况。有一种是两个点直接经过中间的路径相连,这个满足合并性,很容易维护。然后就是某一个点(或两个点)从两边绕了一下,由上到下或由下到上,然后走中间了路径相连的情况。

(借用官方的一张图)

对于第二种情况,考虑它应该是是什么样子的。注意这张图总共就两行,那么这个东西一定是从上面一行走横着的边到某一个位置,走一条竖着的边,然后再到下面连续走横着的边。

所以,我们对于某一个位置能否到达其对应位置,只需要维护其横向能到达的最远位置,以及这两个位置之间有没有纵向边即可。

确定位置只需要维护横向连通性,然后线段树二分即可。

横向连通性满足合并性,总向边可以用数量求和,均可以用线段树维护。

于是此题得解。

关于实现,我们定义每个区间保存一个Node,其中f[0/1][0/1]表示区间左边的上、下能否到区间右边的上下(0上1下),维护linked[0/1]表示区间(0上1下)是否左右全部联通,同时维护sum表示这个区间纵向边数量的和。

对于每一个位置,维护ver表示是否有纵向边,hor[0/1]表示从位置i有没有到位置i+1的横向边(0上1下)。

合并的话节点直接用左右状态判,和很容易转移。

查询位置的线段树二分,无非就是先向上走再向下走,自行脑补一发即可(不会看代码)。

最终判定的时候用了一下状压,仅能判定上面的点用1,仅能判定下面用2,如果上下联通,则均可判定,用3来表示。

最后上代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define debug cout
  6 using namespace std;
  7 const int maxn=1e5+1e2;
  8
  9 int l[maxn<<3],r[maxn<<3],lson[maxn<<3],rson[maxn<<3],fa[maxn<<3];
 10 int linked[maxn<<3][2],ver[maxn],hor[maxn][2];
 11 int sum[maxn<<3];
 12
 13 struct Node {
 14     int f[2][2];
 15     int* operator [] (const int &x) {
 16         return f[x];
 17     }
 18     Node() {
 19         memset(f,0,sizeof(f));
 20     }
 21 }ns[maxn<<3];
 22 int n,m,cnt;
 23
 24 inline Node merge(int* h,Node a,Node b) {
 25     Node ret;
 26     ret.f[0][0] = ( a[0][0]&h[0]&b[0][0] ) | ( a[0][1]&h[1]&b[1][0] );
 27     ret.f[1][1] = ( a[1][1]&h[1]&b[1][1] ) | ( a[1][0]&h[0]&b[0][1] );
 28     ret.f[0][1] = ( a[0][0]&h[0]&b[0][1] ) | ( a[0][1]&h[1]&b[1][1] );
 29     ret.f[1][0] = ( a[1][1]&h[1]&b[1][0] ) | ( a[1][0]&h[0]&b[0][0] );
 30     return ret;
 31 }
 32
 33 inline void build(int pos,int ll,int rr) {
 34     l[pos] = ll , r[pos] = rr;
 35     if( ll == rr ) {
 36         ns[pos][0][0] = ns[pos][1][1] = 1;
 37         linked[pos][0] = linked[pos][1] = 1;
 38         return;
 39     }
 40     const int mid = ( ll + rr ) >> 1;
 41     build(lson[pos]=++cnt,ll,mid);
 42     build(rson[pos]=++cnt,mid+1,rr);
 43     fa[lson[pos]] = fa[rson[pos]] = pos;
 44 }
 45 inline void update_ver(int pos,int tar,int sta) {
 46     if( tar < l[pos] || r[pos] < tar )
 47         return;
 48     if( l[pos] == r[pos] ) {
 49         sum[pos] = ver[tar] = sta;
 50         ns[pos][0][1] = ns[pos][1][0] = sta;
 51         return;
 52     }
 53     const int mid = ( l[pos] + r[pos] ) >> 1;
 54     update_ver(lson[pos],tar,sta);
 55     update_ver(rson[pos],tar,sta);
 56     ns[pos] = merge(hor[mid],ns[lson[pos]],ns[rson[pos]]);
 57     sum[pos] = sum[lson[pos]] + sum[rson[pos]]; // remember this
 58 }
 59 inline void update_hor(int pos,int tar,int at,int sta) {
 60     if( tar < l[pos] || r[pos] < tar )
 61         return;
 62     if( l[pos] == r[pos] ) {
 63         hor[tar][at] = sta;
 64         return;
 65     }
 66     const int mid = ( l[pos] + r[pos] ) >> 1;
 67     update_hor(lson[pos],tar,at,sta);
 68     update_hor(rson[pos],tar,at,sta);
 69     ns[pos] = merge(hor[mid],ns[lson[pos]],ns[rson[pos]]);
 70     linked[pos][0] = linked[lson[pos]][0] & hor[mid][0] & linked[rson[pos]][0],
 71     linked[pos][1] = linked[lson[pos]][1] & hor[mid][1] & linked[rson[pos]][1];
 72 }
 73 inline Node querymid(int pos,int ll,int rr) {
 74     if( !pos )
 75         exit(0);
 76     if( ll <= l[pos] && r[pos] <= rr )
 77         return ns[pos];
 78     const int mid = ( l[pos] + r[pos] ) >> 1;
 79     if( rr <= mid )
 80         return querymid(lson[pos],ll,rr);
 81     if( ll > mid )
 82         return querymid(rson[pos],ll,rr);
 83     return merge(hor[mid],querymid(lson[pos],ll,rr),querymid(rson[pos],ll,rr));
 84 }
 85 inline int queryver(int pos,int ll,int rr) {
 86     if( rr < l[pos] || r[pos] < ll )
 87         return 0;
 88     if( ll <= l[pos] && r[pos] <= rr )
 89         return sum[pos];
 90     return queryver(lson[pos],ll,rr) + queryver(rson[pos],ll,rr);
 91 }
 92 inline int downleft(int pos,int at) {
 93     if( l[pos] == r[pos] )
 94         return l[pos];
 95     const int mid = ( l[pos] + r[pos] ) >> 1;
 96     if( hor[mid][at] && linked[rson[pos]][at] )
 97         return downleft(lson[pos],at);
 98     return downleft(rson[pos],at);
 99 }
100 inline int leftup(int pos,int at) {
101     if( pos == 1 )
102         return 1;
103     if( pos == lson[fa[pos]] )
104         return leftup(fa[pos],at);
105     const int fmid = l[pos] - 1;
106     if( hor[fmid][at] ) {
107         if( linked[lson[fa[pos]]][at] )
108             return leftup(fa[pos],at);
109         return downleft(lson[fa[pos]],at);
110     }
111     return l[pos];
112 }
113 inline int downright(int pos,int at) {
114     if( l[pos] == r[pos] )
115         return r[pos];
116     const int mid = ( l[pos] + r[pos] ) >> 1;
117     if( hor[mid][at] && linked[lson[pos]][at] )
118         return downright(rson[pos],at);
119     return downright(lson[pos],at);
120 }
121 inline int rightup(int pos,int at) {
122     if( pos == 1 )
123         return n;
124     if( pos == rson[fa[pos]] )
125         return rightup(fa[pos],at);
126     const int fmid = r[pos];
127     if( hor[fmid][at] ) {
128         if( linked[rson[fa[pos]]][at] )
129             return rightup(fa[pos],at);
130         return downright(rson[fa[pos]],at);
131     }
132     return r[pos];
133 }
134 inline int findpos(int pos,int tar) {
135     while( l[pos] != r[pos] ) {
136         const int mid = ( l[pos] + r[pos] ) >> 1;
137         if( tar <= mid )
138             pos = lson[pos];
139         else
140             pos = rson[pos];
141     }
142     return pos;
143 }
144
145 inline void solve_case(int x,int y,int xx,int yy) {
146     int sta = y , stb = yy , ans = 0;
147     const int mostl = max( leftup(findpos(1,x),0) , leftup(findpos(1,x),1) );
148     const int mostr = min( rightup(findpos(1,xx),0) , rightup(findpos(1,xx),1) );
149     if( queryver(1,mostl,x) )
150         sta = 3;
151     if( queryver(1,xx,mostr) )
152         stb = 3;
153     Node md = querymid(1,x,xx);
154     for(int i=0;i<2;i++)
155         for(int j=0;j<2;j++)
156             if( ( sta & (1<<i) ) && ( stb & (1<<j) ) )
157                 ans |= md[i][j];
158     puts(ans?"Y":"N");
159 }
160
161 char com[10];
162 int x,y,xx,yy;
163
164 inline void explain() {
165     int sta = *com == 'O';
166     if( y == yy )
167         update_hor(1,x,y-1,sta);
168     else if( x == xx ) {
169         update_ver(1,x,sta);
170     }
171 }
172
173 int main() {
174     scanf("%d",&n);
175     build(cnt=1,1,n);
176     int cc = 0;
177     while( scanf("%s",com) == 1 && *com != 'E' ) {
178         scanf("%d%d%d%d",&y,&x,&yy,&xx);
179         if( x > xx )
180             swap(x,xx) , swap(y,yy);
181         if( *com == 'A' )
182             solve_case(x,y,xx,yy);
183         else
184             explain();
185     }
186
187     return 0;
188
189 }

转载于:https://www.cnblogs.com/Cmd2001/p/8127620.html

Bzoj1018[SHOI2008]堵塞的交通traffic(线段树)相关推荐

  1. BZOJ[1018][SHOI2008]堵塞的交通traffic 线段树

    传送门ber~ 哇这个线段树好神啊!! 用线段树维护图连通性,每个节点开个二维数组 ai,j a i , j a_{i,j}表示这个区间最左面的第 i i i行能不能走到最右面的第j" ro ...

  2. BZOJ 1018: [SHOI2008]堵塞的交通traffic(线段树分治+并查集)

    传送门 解题思路 可以离线,然后确定每个边的出现时间,算这个排序即可.然后就可以线段树分治了,连通性用并查集维护,因为要撤销,所以要按秩合并,时间复杂度\(O(nlog^2 n)\) 代码 #incl ...

  3. BZOJ1018 | SHOI2008-堵塞的交通traffic——线段树维护区间连通性+细节

    [题目描述] BZOJ1018 | SHOI2008-堵塞的交通traffic 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可 以被看成是一个2行C列 ...

  4. BZOJ1018 [SHOI2008] 堵塞的交通traffic

    @(BZOJ)[线段树] Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可 以被看成是一个\(2\)行\(C\)列的矩形网格,网 ...

  5. bzoj1018[SHOI2008]堵塞的交通traffic

    题目链接:bzoj1018 题目大意: 一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个城市和3C-2条道路. 交通信息可以分为以下几种格式: Close ...

  6. Bzoj1018 [SHOI2008]堵塞的交通traffic

    Time Limit: 3 Sec  Memory Limit: 162 MB Submit: 3458  Solved: 1158 Description 有一天,由于某种穿越现象作用,你来到了传说 ...

  7. BZOJ1018: [SHOI2008]堵塞的交通traffic

    线段树维护每一块左上到左下.右上到右下.左上到右上.左下到右下.左上到右下.左下到右上的联通情况. upd:可以直接用3082的方法搞,能过. #include<bits/stdc++.h> ...

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

    二次联通门 : BZOJ 1018: [SHOI2008]堵塞的交通traffic /*BZOJ 1018: [SHOI2008]堵塞的交通traffic麻麻这题玩我这题简直消磨人的意志写了一天了写一 ...

  9. [BZOJ1018]SHOI2008堵塞的交通|线段树

    好神的线段树题,以前只会维护区间什么数值信息的,竟然还可以维护联通性,好题啊,涨姿势了.. 由于只有两行嘛,要保证线段树节点有可加性,我们维护六个信息,分别是右上到右下,右上到左上,右上到左下,右下到 ...

最新文章

  1. 如何查找并干掉僵尸进程
  2. linux制作共享服务器,Linux如何制作一个简单的共享服务器
  3. 在OR项目中使用火焰图
  4. 安卓学习第17课——Gallery
  5. 晒一下MAC下终端颜色配置
  6. gpio 树莓派3a+_树莓派4正式发布:35美元起售!真香
  7. 判断文本的行数c语言,软件工程统计文件中字符串个数,单词个数,词频,行数
  8. 轻量级日志收集转发 | fluent-bit指令详解(一)
  9. 开发方法---形式化方法
  10. 【游戏开发实战】Unity逆向怀旧经典游戏《寻秦OL》,解析二进制动画文件生成预设并播放(资源逆向 | 二进制 | C#)
  11. Unity插件——Odin 学习笔记(一)
  12. 百度AI图像识别——红酒识别、货币识别、车辆检测等
  13. 手动安装VMware Tools
  14. 2022年国家自然基金标书撰写要点的全解
  15. 新生报到系统_中大深圳校区欢迎你!5个院系1271名本科新生报到
  16. ai的预览模式切换_ai模式切换快捷键是什么,Adobe Illustrator模式切换快捷键是什么?...
  17. lis中hl7接口 java_hl7接口开发商中文使用手册
  18. windows 逆向技术必备知识(书籍)
  19. 查看服务器上Docker镜像 latest具体版本
  20. 数据库想法整合,多表联立交互

热门文章

  1. 视觉词袋模型BOW学习笔记及matlab编程实现
  2. cygwin恢复桌面快捷方式
  3. SpringBoot项目配置disconf
  4. 你的微信绑定了银行卡,要记得调整这2个设置,防止资金被盗刷
  5. 结队--复利计算再升级
  6. android 自定义加载动画效果,Android自定义View实现loading动画加载效果
  7. 关于原码、反码、补码、和求补区别总结
  8. 关于PNG和JPG两种图片的常识
  9. 超松驰迭代法SOR_解线性方程组的迭代法
  10. React/React Native框架的设计思想