BZOJ1018 [SHOI2008]堵塞的交通traffic
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
Description
有一天,由于某种穿越现象作用,你来到了传说中的小人国。小人国的布局非常奇特,整个国家的交通系统可
以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个
城市和3C-2条道路。 小人国的交通状况非常槽糕。有的时候由于交通堵塞,两座城市之间的道路会变得不连通,
直到拥堵解决,道路才会恢复畅通。初来咋到的你决心毛遂自荐到交通部某份差事,部长听说你来自一个科技高度
发达的世界,喜出望外地要求你编写一个查询应答系统,以挽救已经病入膏肓的小人国交通系统。 小人国的交通
部将提供一些交通信息给你,你的任务是根据当前的交通情况回答查询的问题。交通信息可以分为以下几种格式:
Close r1 c1 r2 c2:相邻的两座城市(r1,c1)和(r2,c2)之间的道路被堵塞了;Open r1 c1 r2 c2:相邻的两座城
市(r1,c1)和(r2,c2)之间的道路被疏通了;Ask r1 c1 r2 c2:询问城市(r1,c1)和(r2,c2)是否连通。如果存在一
条路径使得这两条城市连通,则返回Y,否则返回N;
Input
第一行只有一个整数C,表示网格的列数。接下来若干行,每行为一条交通信息,以单独的一行“Exit”作为
结束。我们假设在一开始所有的道路都是堵塞的。我们保证 C小于等于100000,信息条数小于等于100000。
Output
对于每个查询,输出一个“Y”或“N”。
Sample Input
Open 1 1 1 2
Open 1 2 2 2
Ask 1 1 2 2
Ask 2 1 2 2
Exit
Sample Output
N
正解:线段树
解题报告:
4月份的时候做过这道题,才发现线段树可以这么玩...的的确确还有很多线段树的神奇之处没有被我发现...
这道题的巧妙之处就在于它的线段是维护的是一个矩形内部的连通性。考虑对于一个矩形,我们用6个变量即可表示出两两的连通情况,不妨从1到6编号。线段树的叶子结点维护的是最小的矩形,也就是长宽都为1的。而这个矩形的上一级就是相邻两个矩形的组合而成的2*1的矩形。可以发现中间有一列被两边矩形所共用,我们就可以根据分类讨论,从两个儿子结点推得父亲结点的连通情况。
那么我用两个线段树,一个表示实际的道路开通情况(这个其实可以不用线段树,这里方便起见也一起用线段树),另一个表示连通情况。那么修改的时候修改前者并且从底往上重新推出连通情况就可以了。
至于询问的话,就要费一点功夫了。我们先考虑在同一列的情况,那毫无疑问,查一下以这一列为右端的矩形和这一列为左端的矩形,直接判掉即可。
如果不在同一列呢?
我们考虑如果直接查询这两列之间的矩阵,然后根据两个点处在哪一行来判断的话会忽略一种情况:从左边绕一大圈,或者从右边绕一大圈然后连通。
也就是说我并不知道可不可以绕道连通。解决办法是查询这两列两边的矩阵,来更新中间矩阵的连通关系,再做判断,这样就可以保证正确性了。BZOJ似乎放了一份题解,虽然讲的不详细但是附了一幅图,图片还比较清楚地表现了上述情况。
细节比较多,不写拍很虚啊!这种题考场上不拍的话期望得分0分。
//It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
const int inf = (<<);
const int MAXN = ;
int n,ql,qr,pos,CC,type;
char ch[];
bool ok;
struct node{
int l,r;
int s,x,z,y,zxys,zsyx;//1、2、3、4、5、6
}t[MAXN*],a[MAXN*],t1,t2,ans,ini;
//t维护连通性,a维护实际开通的道路 inline int getint()
{
int w=,q=; char c=getchar();
while((c<'' || c>'') && c!='-') c=getchar(); if(c=='-') q=,c=getchar();
while (c>='' && c<='') w=w*+c-'', c=getchar(); return q ? -w : w;
} inline void count(node &q){
q.zsyx|=(q.s && q.y) | (q.z && q.x);
q.zxys|=(q.x && q.y) | (q.z && q.s);
if(!q.s) q.s=(q.zsyx && q.y) | (q.z && q.zxys);
if(!q.x) q.x=(q.zxys && q.y) | (q.z && q.zsyx);
if(!q.z) q.z=(q.zsyx && q.x) | (q.zxys && q.s);
if(!q.y) q.y=(q.x && q.zxys) | (q.s && q.zsyx);
} inline node merge(node q,node qq){
node tmp=ini; tmp.z=q.z; tmp.y=qq.y;
if(!tmp.z) tmp.z=(q.s && qq.s && qq.y && qq.x && q.x);
if(!tmp.y) tmp.y=(q.s && qq.s && q.z && q.x && qq.x);
tmp.s=(q.s && qq.s) | (q.zsyx && qq.zxys);
tmp.x=(q.x && qq.x) | (q.zxys && qq.zsyx);
tmp.zsyx=(q.s && qq.zsyx) | (q.zsyx && qq.x);//!!!
tmp.zxys=(q.x && qq.zxys) | (q.zxys && qq.s);//!!!
count(tmp);
return tmp;
} inline void query(int root,int l,int r){
if(ql<=l && r<=qr) {
if(!ok) ans=t[root],ok=true;
else ans=merge(ans,t[root]);
return ;
}
int mid=(l+r)>>,lc=root*,rc=lc+;
if(ql<=mid) query(lc,l,mid);
if(qr>mid) query(rc,mid+,r);
} inline void update(int root,int l,int r){
if(l==r) {
if(CC==) a[root].s=type; else if(CC==) a[root].x=type;
else if(CC==) a[root].z=type; else if(CC==) a[root].y=type;
t[root]=a[root]; count(t[root]);
return ;
}
int mid=(l+r)/; int lc=root*,rc=lc+;
if(pos<=mid) update(lc,l,mid); else update(rc,mid+,r);
t[root]=merge(t[lc],t[rc]); count(t[root]);
}
inline void build(int root,int l,int r){ a[root].l=t[root].l=l; a[root].r=t[root].r=r; if(l==r) return ; int mid=(l+r)/; int lc=root*,rc=lc+; build(lc,l,mid); build(rc,mid+,r); }
inline void out(int oo){ if(oo) printf("Y\n"); else printf("N\n"); }
inline void init_query(int l,int r){ ql=l; qr=r; ok=false; query(,,n); ans.l=l;ans.r=r; }
inline void work(){
n=getint(); n--; int r1,c1,r2,c2; build(,,n);
int acnt=;
while() {
scanf("%s",ch); if(ch[]=='E') break;
r1=getint(); c1=getint(); r2=getint(); c2=getint();
if(c1>c2) swap(c1,c2),swap(r1,r2);
if(ch[]=='A') {
acnt++;
if(acnt==) {
acnt++;
acnt--;
}
if(c1==c2){//同一列
if(c1==) out(t[].z); else if(c1==n+) out(t[].y);
else{
init_query(,c1-); t1=ans;
init_query(c1,n);/*!!!*/ t2=ans;
if(t1.y || t2.z) out(); else out();
}
}
else{//不同列
if(c1>) { init_query(,c1-); t1=ans; } else t1=ini;
if(c2<n+) { init_query(c2,n); t2=ans; } else t2=ini;
init_query(c1,c2-);
if(!ans.z) ans.z=t1.y | (t1.s && t1.x && t1.z);
if(!ans.y) ans.y=t2.z | (t2.s && t2.x && t2.y);
count(ans);
if(r1== && r2==) out(ans.s);
else if(r1== && r2==) out(ans.zsyx);
else if(r1== && r2==) out(ans.zxys);
else if(r1== && r2==) out(ans.x);
}
}
else{
if(ch[]=='O') type=; else type=;
if(r1==r2) {//同行
pos=c1; if(r1==) CC=; else CC=;
update(,,n);
}
else{//同列
if(c1<n+) { pos=c1; CC=; update(,,n); }
if(c1>) { pos=c1-; CC=; update(,,n); }
}
}
}
} int main()
{
work();
return ;
}
BZOJ1018 [SHOI2008]堵塞的交通traffic的更多相关文章
- bzoj千题计划108:bzoj1018: [SHOI2008]堵塞的交通traffic
http://www.lydsy.com/JudgeOnline/problem.php?id=1018 关键点在于只有两行 所以一个2*m矩形连通情况只有6种 编号即对应代码中的a数组 线段树维护 ...
- [BZOJ1018][SHOI2008]堵塞的交通traffic 线段树维护连通性
1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec Memory Limit: 162 MB Submit: 3795 Solved: 1253 [Sub ...
- 【离线 撤销并查集 线段树分治】bzoj1018: [SHOI2008]堵塞的交通traffic
本题可化成更一般的问题:离线动态图询问连通性 当然可以利用它的特殊性质,采用在线线段树维护一些标记的方法 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常 ...
- 【线段树】bzoj1018 [SHOI2008]堵塞的交通traffic
线段树的每个叶子节点存一列. 每个节点维护六个域,分别是左上左下.左上右上.左上右下.左下右上.左下右下.右上右下在区间内部的连通性,不考虑绕出去的情况. 初始每个叶子的左上左下.右上右下是连通的. ...
- Bzoj1018[SHOI2008]堵塞的交通traffic(线段树)
这题需要维护连通性,看到有连接删除,很容易直接就想LCT了.然而这题点数20w操作10w,LCT卡常估计过不去.看到这个东西只有两行,考虑能否用魔改后的线性数据结构去维护.我想到了线段树. 考虑如果两 ...
- bzoj1018[SHOI2008]堵塞的交通traffic——线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1018 巧妙的线段树.维护矩阵四个角的连通性. 考虑两个点连通的可能路径分成3部分:两点左边. ...
- [BZOJ1018][SHOI2008]堵塞的交通traffic 时间分治线段树
题面 介绍一种比较慢的但是好想的做法. 网上漫天的线段树维护联通性,然后想起来费很大周折也很麻烦.我的做法也是要用线段树的,不过用法完全不同. 这个东西叫做时间分治线段树. 首先我们建一个\(1..m ...
- [bzoj1018][SHOI2008]堵塞的交通traffic_线段树
bzoj-1018 SHOI-2008 堵塞的交通traffic 参考博客:https://www.cnblogs.com/MashiroSky/p/5973686.html 题目大意:有一天,由于某 ...
- 【BZOJ1018】[SHOI2008]堵塞的交通traffic 线段树
[BZOJ1018][SHOI2008]堵塞的交通traffic Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个 ...
随机推荐
- KeyBord事件从Activtiy层往下分发详细过程代码示例
step1:调用Activity成员函数dispatchKeyEvent public boolean dispatchKeyEvent(KeyEvent event) { // Let action ...
- noi题库(noi.openjudge.cn) 1.9编程基础之顺序查找T01——T05
T01 查找特定元素的值 描述 在一个序列(下标从1开始)中查找一个给定的值,输出第一次出现的位置. 输入 第一行包含一个正整数n,表示序列中元素个数.1 <= n <= 10000.第二 ...
- 打印机设置(PrintDialog)、页面设置(PageSetupDialog) 及 RDLC报表如何选择指定打印机
如果一台电脑同时连接多个打印机,而且每个打印机使用的纸张大小各不相同(比如:票据打印钱用的小票专用张,办公打印机用的是A4标准纸),在处理打印类的需求时,如果不用代码干预,用户必须每次打印时,都必须在 ...
- RelayCommand
RelayCommand Mvvm最大的特点就是分离了View和ViewModel,将数据的显示和业务逻辑分开.使用WPF的Binding,我们不仅能够 将数据从ViewModel绑定到View,同时 ...
- 数据字典生成工具之旅(6):NVelocity语法介绍及实例
本章开始将会为大家讲解NVelocity的用法,并带领大家实现一个简单的代码生成器. NVelocity是一个基于.NET的模板引擎(template engine).它允许任何人仅仅简单的使用模板语 ...
- Pattern Recognition And Machine Learning读书会前言
读书会成立属于偶然,一次群里无聊到极点,有人说Pattern Recognition And Machine Learning这本书不错,加之有好友之前推荐过,便发了封群邮件组织这个读书会,采用轮流讲 ...
- HoloLens开发手记 - 应用程序模型 App model
HoloLens使用Universal Windows Platform (UWP)提供的应用模型.UWP应用模型定义了应用如何被安全和完全地安装.更新.版本控制和移除.它管理了应用生命周期 - 应用 ...
- [转] Asp.net vNext webapi 自托管
[声明]本文转自:http://www.cnblogs.com/ListenCode/p/4206204.html 转载需注明! 微软推出的Asp.net vNext(asp.net 5.0)的其中的 ...
- SqlServer——批量操作(批量添加,删除)
批量添加数据: 一条insert语句批量插入多条记录 常见的insert语句,向数据库中,一条语句只能插入一条数据: insert into persons (id_p, lastname , fir ...
- SSH框架 sequence diagram