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来表示。
最后上代码:
#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(线段树)的更多相关文章
- [BZOJ1018][SHOI2008]堵塞的交通traffic 线段树维护连通性
1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec Memory Limit: 162 MB Submit: 3795 Solved: 1253 [Sub ...
- bzoj1018[SHOI2008]堵塞的交通traffic——线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1018 巧妙的线段树.维护矩阵四个角的连通性. 考虑两个点连通的可能路径分成3部分:两点左边. ...
- [bzoj1018][SHOI2008]堵塞的交通traffic_线段树
bzoj-1018 SHOI-2008 堵塞的交通traffic 参考博客:https://www.cnblogs.com/MashiroSky/p/5973686.html 题目大意:有一天,由于某 ...
- 【BZOJ1018】[SHOI2008]堵塞的交通traffic 线段树
[BZOJ1018][SHOI2008]堵塞的交通traffic Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个 ...
- BZOJ 1018: [SHOI2008]堵塞的交通traffic [线段树 区间信息]
1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 3064 Solved: 1027[Submi ...
- 【bzoj1018】[SHOI2008]堵塞的交通traffic 线段树区间合并+STL-set
题目描述 给出一张2*n的网格图,初始每条边都是不连通的.多次改变一条边的连通性或询问两个点是否连通. 输入 第一行只有一个整数C,表示网格的列数.接下来若干行,每行为一条交通信息,以单独的一行“Ex ...
- BZOJ1018 SHOI2008堵塞的交通(线段树)
动态图的连通性当然是可以用LCT维护的.但这相当的不优美,毕竟这样做没有用到任何该图的性质,LCT自带的大常数也会使其跑得非常慢. 考虑用线段树维护区间左右端四个点之间各自的连通性(仅经过该区间内路径 ...
- BZOJ 1018: [SHOI2008]堵塞的交通traffic(线段树分治+并查集)
传送门 解题思路 可以离线,然后确定每个边的出现时间,算这个排序即可.然后就可以线段树分治了,连通性用并查集维护,因为要撤销,所以要按秩合并,时间复杂度\(O(nlog^2 n)\) 代码 #incl ...
- 【BZOJ1018】堵塞的交通(线段树)
[BZOJ1018]堵塞的交通(线段树) 题面 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可 以被看成是一个2行C列的矩形网 ...
随机推荐
- 在linux上安装完oracle数据库后,如何修改ORACLE_HOSTNAME
1.修改HOSTS文件,添加node2到本机IP地址的映射: [root@node2home]# gedit /etc/hosts 最后一行为添加的: 127.0.0.1 localhost loca ...
- imperva 默认策略添加例外
创建违规访问 检查违规的告警类型 假如客户的这个目录下真的有这个文件,而且客户非常明确这是一个正常且安全的东西怎么办?我该如何的将它添加到例外? 添加例外的步骤: 再次构造违规的请求: 默认策略添加例 ...
- Linux机器如何在公司内网配置代理
一.通过上网认证 必须在图形界面下使用浏览器(如Firefox)完成上网认证过程. 请先确保本机已经可以正常访问公司内部网络. Firefox上配置代理: 1)打开Firefox首选项,[高级]-[网 ...
- bzoj 1083 繁忙的都市
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1083 题解: 在bzoj里能遇到如此如此水的题真是不容易…… 乍一看好像有点吓人,其实是一 ...
- 22 Gobs of data 设计和使用采集数据的包
Gobs of data 24 March 2011 Introduction To transmit a data structure across a network or to store it ...
- 04 Effective Go 高效的go语言 重点内容
Effective Go 高效的go语言 Introduction 介绍 Examples 例子 Formatting 格式 Commentary 评论 Names 名字 Package names ...
- angular架构
angular架构包括以下部分: 1.模块 2.组件 3.模板 4.元数据 5.数据绑定 6.指令 7.服务 8.依赖注入 9.动画 10.变更检测 11.事件 12.表单 13.HTTP 14.生命 ...
- Python_oldboy_自动化运维之路(二)
本节内容: 1.pycharm工具的使用 2.进制运算 3.表达式if ...else语句 4.表达式for 循环 5.break and continue 6.表达式while 循环 1.pycha ...
- tomcat数据源配置DBCP
原文件: https://www.cnblogs.com/sicd/p/4053780.html DBCP object created 日期 by the following code was ne ...
- 洛谷P2024食物链
传送门啦 这道题的特殊之处在于对于任意一个并查集,只要告诉你某个节点的物种,你就可以知道所有节点对应的物种. 比如一条长为4的链 甲->乙->丙->丁 ,我们知道乙是A物种.那么甲一 ...