1018: [SHOI2008]堵塞的交通traffic
Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 3166 Solved: 1056
[ Submit][ Status][ Discuss]
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
HINT
Source
第一次看到用线段树维护连通性的题。。。
直接从最麻烦的情况入手好了,因为能解决最麻烦问题的程序总是能解决较简单的情形的
假如是从A走到D,不妨假设总有ca < cd
只考虑图示矩形内部的边的话,A到D的路径只能经过往右往上往下三种方向的边
这样的信息线段树显然可以直接维护,一个矩形可以用线段树上logn个节点表示,
于是,回答的时候只要两两之间再判一下连通性即可
不过这样显然没考虑完全所有情况
考虑图中的点B和C,假如A,D不能直接用这种简单的方法连通,那就一定得用这两个点辅助了
比如如果想要用A左边的边,那一定会在再次进入矩形的时候经过B
因为如果回来不经过B,那。。。。。为什么要走出去啊?
因此,A到B的路径是A往左一段接着往下然后一直往右
同理,C到D时往右往下往左
综合以上信息,就能轻易看出ABCD四个点之间的连通性,问题也就解决了
反正就是各种分类讨论,线段树总是能维护,挺码农的(可能是因为我姿势丑?)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1E5 + 10;
const int T = 4;
const int INF = ~0U>>1;
struct data{
bool f0,f1,f2,f3; data(){f0 = f1 = f2 = f3 = 0;}
}f[maxn*T];
int n,tp,stk[maxn],L[maxn]; char s[10];
bool E[2][maxn][3],ug[maxn*T],dg[maxn*T],h[maxn*T];
int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret * 10 + ch - '0',ch = getchar();
return ret;
}
int getcom()
{
scanf("%s",s + 1);
if (s[1] == 'C') return 1;
if (s[1] == 'O') return 2;
if (s[1] == 'A') return 3;
return 4;
}
data Merge(const data &A,const data &B,const int &l)
{
data r1,r2; bool *e0 = E[0][l],*e1 = E[1][l];
if ((A.f0 && e0[0]) || (A.f1 && e1[0] && e1[2])) r1.f0 = 1;
if ((A.f1 && e1[0]) || (A.f0 && e0[0] && e0[2])) r1.f1 = 1;
if ((A.f2 && e0[0]) || (A.f3 && e1[0] && e1[2])) r1.f2 = 1;
if ((A.f3 && e1[0]) || (A.f2 && e0[0] && e0[2])) r1.f3 = 1;
if ((r1.f0 && B.f0) || (r1.f1 && B.f2)) r2.f0 = 1;
if ((r1.f0 && B.f1) || (r1.f1 && B.f3)) r2.f1 = 1;
if ((r1.f2 && B.f0) || (r1.f3 && B.f2)) r2.f2 = 1;
if ((r1.f2 && B.f1) || (r1.f3 && B.f3)) r2.f3 = 1;
return r2;
}
void Modify(int o,int l,int r,int pos)
{
if (l == r) {h[o] = E[0][l][2]; return;}
int mid = (l + r) >> 1;
if (pos <= mid) Modify(o<<1,l,mid,pos);
else Modify(o<<1|1,mid+1,r,pos);
f[o] = Merge(f[o<<1],f[o<<1|1],mid+1);
ug[o] = (ug[o<<1] && ug[o<<1|1] && E[0][mid][1]) ? 1 : 0;
dg[o] = (dg[o<<1] && dg[o<<1|1] && E[1][mid][1]) ? 1 : 0;
h[o] = (h[o<<1] || h[o<<1|1]) ? 1 : 0;
}
void Add_block(int o,int l,int r,int ql,int qr)
{
if (ql <= l && r <= qr) {stk[++tp] = o; L[tp] = l; return;}
int mid = (l + r) >> 1;
if (ql <= mid) Add_block(o<<1,l,mid,ql,qr);
if (qr > mid) Add_block(o<<1|1,mid+1,r,ql,qr);
}
int Query_Right(int o,int l,int r,int ql,int qr)
{
if (!h[o]) return 0; if (l == r) return l;
int mid = (l + r) >> 1,ret = 0;
if (ql <= l && r <= qr)
{
if (h[o<<1|1]) return Query_Right(o<<1|1,mid+1,r,ql,qr);
if (h[o<<1]) return Query_Right(o<<1,l,mid,ql,qr);
return 0;
}
if (qr > mid) ret = Query_Right(o<<1|1,mid+1,r,ql,qr);
return ret ? ret : Query_Right(o<<1,l,mid,ql,qr);
}
int Query_Left(int o,int l,int r,int ql,int qr)
{
if (!h[o]) return INF; if (l == r) return l;
int mid = (l + r) >> 1,ret = INF;
if (ql <= l && r <= qr)
{
if (h[o<<1]) return Query_Left(o<<1,l,mid,ql,qr);
if (h[o<<1|1]) return Query_Left(o<<1|1,mid+1,r,ql,qr);
return INF;
}
if (ql <= mid) ret = Query_Left(o<<1,l,mid,ql,qr);
return ret != INF ? ret : Query_Left(o<<1|1,mid+1,r,ql,qr);
}
bool Connect(int l,int r)
{
tp = 0; Add_block(1,1,n,l,r);
for (int i = 2; i <= tp; i++)
{
if (!ug[stk[i]] || !dg[stk[i]]) return 0;
if (!E[0][L[i]][0] || !E[1][L[i]][0]) return 0;
}
return (ug[stk[1]] & dg[stk[1]]);
}
bool Ask_Left(int c)
{
if (E[0][c][2]) return 1;
if (c > 1)
{
int pos = Query_Right(1,1,n,1,c - 1);
if (!pos) return 0;
return Connect(pos,c);
}
return 0;
}
bool Ask_Right(int c)
{
if (E[1][c][2]) return 1;
if (c < n)
{
int pos = Query_Left(1,1,n,c + 1,n);
if (pos == INF) return 0;
return Connect(c,pos);
}
return 0;
}
bool Ask(int r1,int c1,int r2,int c2,bool flag0,bool flag1)
{
tp = 0; Add_block(1,1,n,c1,c2); data now = f[stk[1]];
for (int i = 2; i <= tp; i++) now = Merge(now,f[stk[i]],L[i]);
if (!r1 || flag0)
{
if (now.f0 && (!r2 || flag1)) return 1;
if (now.f1 && (r2 || flag1)) return 1;
}
if (r1 || flag0)
{
if (now.f2 && (!r2 || flag1)) return 1;
if (now.f3 && (r2 || flag1)) return 1;
}
return 0;
}
void Build(int o,int l,int r)
{
if (l == r)
{
f[o].f0 = f[o].f3 = 1;
ug[o] = dg[o] = 1; return;
}
int mid = (l + r) >> 1;
Build(o<<1,l,mid); Build(o<<1|1,mid+1,r);
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
n = getint(); Build(1,1,n);
for (;;)
{
int com = getcom(),r1,c1,r2,c2;
if (com == 1)
{
r1 = getint(); c1 = getint(); --r1;
r2 = getint(); c2 = getint(); --r2;
if (c1 > c2) swap(r1,r2),swap(c1,c2);
if (c1 == c2) E[0][c1][2] = E[1][c2][2] = 0;
else E[r1][c1][1] = E[r2][c2][0] = 0;
Modify(1,1,n,c1); if (c1 != c2) Modify(1,1,n,c2);
}
else if (com == 2)
{
r1 = getint(); c1 = getint(); --r1;
r2 = getint(); c2 = getint(); --r2;
if (c1 > c2) swap(r1,r2),swap(c1,c2);
if (c1 == c2) E[0][c1][2] = E[1][c1][2] = 1;
else E[r1][c1][1] = E[r2][c2][0] = 1;
Modify(1,1,n,c1); if (c1 != c2) Modify(1,1,n,c2);
}
else if (com == 3)
{
r1 = getint(); c1 = getint(); --r1;
r2 = getint(); c2 = getint(); --r2;
if (c1 > c2) swap(r1,r2),swap(c1,c2);
if (c1 == c2)
{
if (Ask_Left(c1)) {puts("Y"); continue;}
if (Ask_Right(c1)) {puts("Y"); continue;}
puts("N");
}
else
{
bool f0 = Ask_Left(c1),f1 = Ask_Right(c2);
if (Ask(r1,c1,r2,c2,f0,f1)) puts("Y"); else puts("N");
}
}
else break;
}
return 0;
}