Bzoj1018[SHOI2008]堵塞的交通traffic(线段树)
这题需要维护连通性,看到有连接删除,很容易直接就想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(线段树)相关推荐
- BZOJ[1018][SHOI2008]堵塞的交通traffic 线段树
传送门ber~ 哇这个线段树好神啊!! 用线段树维护图连通性,每个节点开个二维数组 ai,j a i , j a_{i,j}表示这个区间最左面的第 i i i行能不能走到最右面的第j" ro ...
- BZOJ 1018: [SHOI2008]堵塞的交通traffic(线段树分治+并查集)
传送门 解题思路 可以离线,然后确定每个边的出现时间,算这个排序即可.然后就可以线段树分治了,连通性用并查集维护,因为要撤销,所以要按秩合并,时间复杂度\(O(nlog^2 n)\) 代码 #incl ...
- BZOJ1018 | SHOI2008-堵塞的交通traffic——线段树维护区间连通性+细节
[题目描述] BZOJ1018 | SHOI2008-堵塞的交通traffic 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可 以被看成是一个2行C列 ...
- BZOJ1018 [SHOI2008] 堵塞的交通traffic
@(BZOJ)[线段树] Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可 以被看成是一个\(2\)行\(C\)列的矩形网格,网 ...
- bzoj1018[SHOI2008]堵塞的交通traffic
题目链接:bzoj1018 题目大意: 一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个城市和3C-2条道路. 交通信息可以分为以下几种格式: Close ...
- Bzoj1018 [SHOI2008]堵塞的交通traffic
Time Limit: 3 Sec Memory Limit: 162 MB Submit: 3458 Solved: 1158 Description 有一天,由于某种穿越现象作用,你来到了传说 ...
- BZOJ1018: [SHOI2008]堵塞的交通traffic
线段树维护每一块左上到左下.右上到右下.左上到右上.左下到右下.左上到右下.左下到右上的联通情况. upd:可以直接用3082的方法搞,能过. #include<bits/stdc++.h> ...
- BZOJ 1018: [SHOI2008]堵塞的交通traffic
二次联通门 : BZOJ 1018: [SHOI2008]堵塞的交通traffic /*BZOJ 1018: [SHOI2008]堵塞的交通traffic麻麻这题玩我这题简直消磨人的意志写了一天了写一 ...
- [BZOJ1018]SHOI2008堵塞的交通|线段树
好神的线段树题,以前只会维护区间什么数值信息的,竟然还可以维护联通性,好题啊,涨姿势了.. 由于只有两行嘛,要保证线段树节点有可加性,我们维护六个信息,分别是右上到右下,右上到左上,右上到左下,右下到 ...
最新文章
- 用InstallShield 打包工具 打 Win32 程序 (depends.exe 用看程序都依赖了哪些dll)
- 一部论述修养人生处世出世的集录_读《菜根谭》,人生本是修心的过程
- ux和ui_他们说,以UX / UI设计师的身份加入一家初创公司。 他们说,这会很有趣。
- 让人吐血的文章,要被气死了
- Linux系统(Centos)下安装nodejs并配置环境
- 2d游戏引擎_8年,从2D到3D,我的学习之路
- 平均数和均值一样吗_求平均数!
- 关于collectionView的一些内容
- My97DatePickerBeta日期控件乱码问题解决方案
- Android中加载ETC2压缩格式(PKM后缀)纹理
- Solidworks常用插件介绍
- war压缩命令_宝塔面板linux版解压WAR文件时,如何解压的三种方法介绍
- IE浏览器怎么设置兼容性 添加兼容站点方法
- Decal Buffer相关
- 2019云计算机峰会,计算机学院师生参加“2019华为云城市峰会”
- python实现单机斗地主手机版下载_单机斗地主(单机版)无需网络下载
- python字符串的定界符可以是_Python中,字符串不能用以下哪个符号作为定界符(): \|'|'''|;...
- SOI七层模型和TCP/IP五层协议:
- 使用lodop设置导出表格的数据格式
- 对话 | 港科大教授权龙:为什么三维重建才是计算机视觉的灵魂?