这题需要维护连通性,看到有连接删除,很容易直接就想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来表示。

最后上代码:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define debug cout
using namespace std;
const int maxn=1e5+1e2; int l[maxn<<],r[maxn<<],lson[maxn<<],rson[maxn<<],fa[maxn<<];
int linked[maxn<<][],ver[maxn],hor[maxn][];
int sum[maxn<<]; struct Node {
int f[][];
int* operator [] (const int &x) {
return f[x];
}
Node() {
memset(f,,sizeof(f));
}
}ns[maxn<<];
int n,m,cnt; inline Node merge(int* h,Node a,Node b) {
Node ret;
ret.f[][] = ( a[][]&h[]&b[][] ) | ( a[][]&h[]&b[][] );
ret.f[][] = ( a[][]&h[]&b[][] ) | ( a[][]&h[]&b[][] );
ret.f[][] = ( a[][]&h[]&b[][] ) | ( a[][]&h[]&b[][] );
ret.f[][] = ( a[][]&h[]&b[][] ) | ( a[][]&h[]&b[][] );
return ret;
} inline void build(int pos,int ll,int rr) {
l[pos] = ll , r[pos] = rr;
if( ll == rr ) {
ns[pos][][] = ns[pos][][] = ;
linked[pos][] = linked[pos][] = ;
return;
}
const int mid = ( ll + rr ) >> ;
build(lson[pos]=++cnt,ll,mid);
build(rson[pos]=++cnt,mid+,rr);
fa[lson[pos]] = fa[rson[pos]] = pos;
}
inline void update_ver(int pos,int tar,int sta) {
if( tar < l[pos] || r[pos] < tar )
return;
if( l[pos] == r[pos] ) {
sum[pos] = ver[tar] = sta;
ns[pos][][] = ns[pos][][] = sta;
return;
}
const int mid = ( l[pos] + r[pos] ) >> ;
update_ver(lson[pos],tar,sta);
update_ver(rson[pos],tar,sta);
ns[pos] = merge(hor[mid],ns[lson[pos]],ns[rson[pos]]);
sum[pos] = sum[lson[pos]] + sum[rson[pos]]; // remember this
}
inline void update_hor(int pos,int tar,int at,int sta) {
if( tar < l[pos] || r[pos] < tar )
return;
if( l[pos] == r[pos] ) {
hor[tar][at] = sta;
return;
}
const int mid = ( l[pos] + r[pos] ) >> ;
update_hor(lson[pos],tar,at,sta);
update_hor(rson[pos],tar,at,sta);
ns[pos] = merge(hor[mid],ns[lson[pos]],ns[rson[pos]]);
linked[pos][] = linked[lson[pos]][] & hor[mid][] & linked[rson[pos]][],
linked[pos][] = linked[lson[pos]][] & hor[mid][] & linked[rson[pos]][];
}
inline Node querymid(int pos,int ll,int rr) {
if( !pos )
exit();
if( ll <= l[pos] && r[pos] <= rr )
return ns[pos];
const int mid = ( l[pos] + r[pos] ) >> ;
if( rr <= mid )
return querymid(lson[pos],ll,rr);
if( ll > mid )
return querymid(rson[pos],ll,rr);
return merge(hor[mid],querymid(lson[pos],ll,rr),querymid(rson[pos],ll,rr));
}
inline int queryver(int pos,int ll,int rr) {
if( rr < l[pos] || r[pos] < ll )
return ;
if( ll <= l[pos] && r[pos] <= rr )
return sum[pos];
return queryver(lson[pos],ll,rr) + queryver(rson[pos],ll,rr);
}
inline int downleft(int pos,int at) {
if( l[pos] == r[pos] )
return l[pos];
const int mid = ( l[pos] + r[pos] ) >> ;
if( hor[mid][at] && linked[rson[pos]][at] )
return downleft(lson[pos],at);
return downleft(rson[pos],at);
}
inline int leftup(int pos,int at) {
if( pos == )
return ;
if( pos == lson[fa[pos]] )
return leftup(fa[pos],at);
const int fmid = l[pos] - ;
if( hor[fmid][at] ) {
if( linked[lson[fa[pos]]][at] )
return leftup(fa[pos],at);
return downleft(lson[fa[pos]],at);
}
return l[pos];
}
inline int downright(int pos,int at) {
if( l[pos] == r[pos] )
return r[pos];
const int mid = ( l[pos] + r[pos] ) >> ;
if( hor[mid][at] && linked[lson[pos]][at] )
return downright(rson[pos],at);
return downright(lson[pos],at);
}
inline int rightup(int pos,int at) {
if( pos == )
return n;
if( pos == rson[fa[pos]] )
return rightup(fa[pos],at);
const int fmid = r[pos];
if( hor[fmid][at] ) {
if( linked[rson[fa[pos]]][at] )
return rightup(fa[pos],at);
return downright(rson[fa[pos]],at);
}
return r[pos];
}
inline int findpos(int pos,int tar) {
while( l[pos] != r[pos] ) {
const int mid = ( l[pos] + r[pos] ) >> ;
if( tar <= mid )
pos = lson[pos];
else
pos = rson[pos];
}
return pos;
} inline void solve_case(int x,int y,int xx,int yy) {
int sta = y , stb = yy , ans = ;
const int mostl = max( leftup(findpos(,x),) , leftup(findpos(,x),) );
const int mostr = min( rightup(findpos(,xx),) , rightup(findpos(,xx),) );
if( queryver(,mostl,x) )
sta = ;
if( queryver(,xx,mostr) )
stb = ;
Node md = querymid(,x,xx);
for(int i=;i<;i++)
for(int j=;j<;j++)
if( ( sta & (<<i) ) && ( stb & (<<j) ) )
ans |= md[i][j];
puts(ans?"Y":"N");
} char com[];
int x,y,xx,yy; inline void explain() {
int sta = *com == 'O';
if( y == yy )
update_hor(,x,y-,sta);
else if( x == xx ) {
update_ver(,x,sta);
}
} int main() {
scanf("%d",&n);
build(cnt=,,n);
int cc = ;
while( scanf("%s",com) == && *com != 'E' ) {
scanf("%d%d%d%d",&y,&x,&yy,&xx);
if( x > xx )
swap(x,xx) , swap(y,yy);
if( *com == 'A' )
solve_case(x,y,xx,yy);
else
explain();
} return ; }

Bzoj1018[SHOI2008]堵塞的交通traffic(线段树)的更多相关文章

  1. [BZOJ1018][SHOI2008]堵塞的交通traffic 线段树维护连通性

    1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec  Memory Limit: 162 MB Submit: 3795  Solved: 1253 [Sub ...

  2. bzoj1018[SHOI2008]堵塞的交通traffic——线段树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1018 巧妙的线段树.维护矩阵四个角的连通性. 考虑两个点连通的可能路径分成3部分:两点左边. ...

  3. [bzoj1018][SHOI2008]堵塞的交通traffic_线段树

    bzoj-1018 SHOI-2008 堵塞的交通traffic 参考博客:https://www.cnblogs.com/MashiroSky/p/5973686.html 题目大意:有一天,由于某 ...

  4. 【BZOJ1018】[SHOI2008]堵塞的交通traffic 线段树

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

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

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

  6. 【bzoj1018】[SHOI2008]堵塞的交通traffic 线段树区间合并+STL-set

    题目描述 给出一张2*n的网格图,初始每条边都是不连通的.多次改变一条边的连通性或询问两个点是否连通. 输入 第一行只有一个整数C,表示网格的列数.接下来若干行,每行为一条交通信息,以单独的一行“Ex ...

  7. BZOJ1018 SHOI2008堵塞的交通(线段树)

    动态图的连通性当然是可以用LCT维护的.但这相当的不优美,毕竟这样做没有用到任何该图的性质,LCT自带的大常数也会使其跑得非常慢. 考虑用线段树维护区间左右端四个点之间各自的连通性(仅经过该区间内路径 ...

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

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

  9. 【BZOJ1018】堵塞的交通(线段树)

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

随机推荐

  1. VUE项目用hbuilder 打包为手机APP

    一.测试项目是否可以正确运行    指令:npm run dev 首先我们先建立一个vue的项目,本人用的是vue-cli随便建立的,然后运行项目 不必非得是像我这样的,这一步的目的只是测试一下咱们的 ...

  2. ubuntu网络连接:Ifupdown(eth0)的连接不能修改或删除

    今天其实遇到了三个问题,一个是ubuntu系统上的网络图标不见了,把网络图标弄出来以后有无法联网,联网成功却变成Ifupdown(eth0)的连接且不能修改或删除. 这里我只记录最后一个问题,前两个问 ...

  3. HTTP与HTTPS相关知识

    URL的开头一般会有http或https,这是访问资源需要的协议类型.有时还会看到ftp.sftp.smb开头的URL,这些都是协议类型.一般使用得最多的还是http和https. HTTP HTTP ...

  4. 85.YCbCr与YUV的区别

    yuv色彩模型来源于rgb模型,该模型的特点是将亮度和色度分离开,从而适合于图像处理领域. YCbCr模型来源于yuv模型,应用于数字视频,ITU-R BT.601 recommendation 通过 ...

  5. 内核工具 – Sparse 简介【转】

    转自:http://www.cnblogs.com/wang_yb/p/3575039.html Sparse是内核代码静态分析工具, 能够帮助我们找出代码中的隐患. 主要内容: Sparse 介绍 ...

  6. java基础65 JavaScript中的Window对象(网页知识)

    1.javaScript组成部分 1.EMCAScript(基本语法)    2.BOM(Browser Object Model):浏览器对象模型            浏览器对象模型中的浏览器的各 ...

  7. MFC中CString.Format类详解

    在MFC程序中,使用CString来处理字符串是一个很不错的选择.CString既可以处理Unicode标准的字符串,也可以处理ANSI标准的字符串.CString的Format方法给我们进行字符串的 ...

  8. 关于SizeOf、Length

    结论: 到底什么时候用Length,SizeOf呢,我总结下使用Length,Sizeof的场景 1.Length(静态数组或动态数组)----没有问题 2.Length(string/shortst ...

  9. CF1030A 【In Search of an Easy Problem】

    题目巨简单,主要是给大家翻译一下 给n个数,其中存在1就输出HARD,否则输出EASY,不区分大小写 #include<iostream> #include<cstdio> u ...

  10. CTF中做Linux下漏洞利用的一些心得

    其实不是很爱搞Linux,但是因为CTF必须要接触一些,漏洞利用方面也是因为CTF基本都是linux的pwn题目. 基本的题目分类,我认为就下面这三种,这也是常见的类型. 下面就分类来说说 0x0.栈 ...