这题需要维护连通性,看到有连接删除,很容易直接就想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. 安卓微信、QQ自带浏览器 UXSS 漏洞

    安卓微信.QQ自带浏览器 UXSS 漏洞 注:PDF报告原文下载链接 Author: hei@knownsec.com Date: 2016-02-29 一.漏洞描述 在安卓平台上的微信及QQ自带浏览 ...

  2. Esper复杂事务处理一小时入门

    来自小韩 什么是Esper 想要认识Esper,先要了解CEP(Complex Event Processing),到处都有,并且各方理解也有偏差,我就不赘述了. Esper就是CEP的一个java的 ...

  3. 渗透测试===kali linux的安装

    方法一: kali linux 安装在本地的vitural box 或者 wm ware中 方法二: 安装在移动硬盘或者储存卡中,插到电脑就能用

  4. 一步一步搭建oracle 11gR2 rac+dg之共享磁盘设置(三)【转】

    一步一步在RHEL6.5+VMware Workstation 10上搭建 oracle 11gR2 rac + dg 之共享磁盘准备 (三) 注意:这一步是配置rac的过程中非常重要的一步,很多童鞋 ...

  5. ASP防XSS代码

    原作是在GitHub上,基于Node.js所写.但是..ASP的JS引擎跟V8又有些不同..于是,嗯.. <% Function AntiXSS_VbsTrim(s) AntiXSS_VbsTr ...

  6. Python subprocess- call、check_call、check_output

    简介 subprocess模块用来创建新的进程,连接到其stdin.stdout.stderr管道并获取它们的返回码.subprocess模块的出现是为了替代如下旧模块及函数:os.system.os ...

  7. Java数据类型以及变量的定义

    1130136248   Java的基本数据类型 变量就是申请内存来存储值.也就是说,当创建变量的时候,需要在内存中申请空间. 内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类 ...

  8. Python全局变量和局部变量

    全局变量和局部变量 定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域. 局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问.调用函数时,所有在函数内声明的变量 ...

  9. git —— 分支

    git中每一个分支相当于一个时间线 并列且相互平行 控制用指针控制~ 1.第一种创建命令: $ git branch 分支名称 —— 创建分支 $ git checkout 分支名称 —— 切换分支 ...

  10. HDU 2476 String painter(区间DP+思维)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2476 题目大意:给你字符串A.B,每次操作可以将一段区间刷成任意字符,问最少需要几次操作可以使得字符串 ...