这题需要维护连通性,看到有连接删除,很容易直接就想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. 在linux上安装完oracle数据库后,如何修改ORACLE_HOSTNAME

    1.修改HOSTS文件,添加node2到本机IP地址的映射: [root@node2home]# gedit /etc/hosts 最后一行为添加的: 127.0.0.1 localhost loca ...

  2. imperva 默认策略添加例外

    创建违规访问 检查违规的告警类型 假如客户的这个目录下真的有这个文件,而且客户非常明确这是一个正常且安全的东西怎么办?我该如何的将它添加到例外? 添加例外的步骤: 再次构造违规的请求: 默认策略添加例 ...

  3. Linux机器如何在公司内网配置代理

    一.通过上网认证 必须在图形界面下使用浏览器(如Firefox)完成上网认证过程. 请先确保本机已经可以正常访问公司内部网络. Firefox上配置代理: 1)打开Firefox首选项,[高级]-[网 ...

  4. bzoj 1083 繁忙的都市

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1083 题解: 在bzoj里能遇到如此如此水的题真是不容易…… 乍一看好像有点吓人,其实是一 ...

  5. 22 Gobs of data 设计和使用采集数据的包

    Gobs of data 24 March 2011 Introduction To transmit a data structure across a network or to store it ...

  6. 04 Effective Go 高效的go语言 重点内容

    Effective Go  高效的go语言 Introduction 介绍 Examples 例子 Formatting 格式 Commentary 评论 Names 名字 Package names ...

  7. angular架构

    angular架构包括以下部分: 1.模块 2.组件 3.模板 4.元数据 5.数据绑定 6.指令 7.服务 8.依赖注入 9.动画 10.变更检测 11.事件 12.表单 13.HTTP 14.生命 ...

  8. Python_oldboy_自动化运维之路(二)

    本节内容: 1.pycharm工具的使用 2.进制运算 3.表达式if ...else语句 4.表达式for 循环 5.break and continue 6.表达式while 循环 1.pycha ...

  9. tomcat数据源配置DBCP

    原文件: https://www.cnblogs.com/sicd/p/4053780.html DBCP object created 日期 by the following code was ne ...

  10. 洛谷P2024食物链

    传送门啦 这道题的特殊之处在于对于任意一个并查集,只要告诉你某个节点的物种,你就可以知道所有节点对应的物种. 比如一条长为4的链 甲->乙->丙->丁 ,我们知道乙是A物种.那么甲一 ...