[bzoj1018][SHOI2008]堵塞的交通traffic【线段树】
【题目描述】
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
【题解】
思路很妙。
考虑用线段树维护连通性。
记 can[2][2] 表示左 上(下) 到右 上(下) 是否连通
这东西可以用线段树维护查询与更改。
考虑一条路线,回头(180°转弯)最多有2次(最两端),形状为:
—— —— —— S —— —— —— —— —— —— ——
| | |
—— —— —— —— —— T —— ——
之类。
所以先把S,T走到不换行能到的最外侧,然后线段树查询连通性。
/* -------------- user Vanisher problem bzoj-1018 ----------------*/ # include <bits/stdc++.h> # define ll long long # define N 100010 using namespace std; int read(){ int tmp=0, fh=1; char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();} while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();} return tmp*fh; } struct Tag{ int o[2][2]; }; struct node{ int pr,l,r; Tag can; }T[N*3]; int o[2][N],place,n; char s[11]; Tag mixed(Tag a, Tag b, int lim){ Tag now={0,0,0,0}; for (int i=0; i<=1; i++) if (o[i][lim]==true){ if (a.o[0][i]&&b.o[i][0]) now.o[0][0]=true; if (a.o[0][i]&&b.o[i][1]) now.o[0][1]=true; if (a.o[1][i]&&b.o[i][0]) now.o[1][0]=true; if (a.o[1][i]&&b.o[i][1]) now.o[1][1]=true; } return now; } int build(int l, int r){ int p=++place; T[p].l=l; T[p].r=r; if (l==r) T[p].can.o[0][0]=T[p].can.o[1][1]=true; else { int mid=(l+r)/2; build(l,mid); T[p].pr=build(mid+1,r); } return p; } void modify1(int p, int x, int tag){ if (T[p].l==T[p].r){ T[p].can.o[0][1]=T[p].can.o[1][0]=tag; return; } int mid=(T[p].l+T[p].r)/2; if (mid>=x) modify1(p+1,x,tag); else modify1(T[p].pr,x,tag); T[p].can=mixed(T[p+1].can,T[T[p].pr].can,mid); } void modify0(int p, int x){ if (T[p].r==x) return; int mid=(T[p].l+T[p].r)/2; if (mid>=x) modify0(p+1,x); else modify0(T[p].pr,x); T[p].can=mixed(T[p+1].can,T[T[p].pr].can,mid); } int queryl(int p, int x, int tag){ if (T[p].r==x&&T[p].can.o[tag][tag]==true) return T[p].l; int mid=(T[p].l+T[p].r)/2; if (mid<x){ int num=queryl(T[p].pr,x,tag); if (num!=mid+1) return num; if (o[tag][mid]==false) return num; return queryl(p+1,mid,tag); } else return queryl(p+1,x,tag); } int queryr(int p, int x, int tag){ if (T[p].l==x&&T[p].can.o[tag][tag]==true) return T[p].r; int mid=(T[p].l+T[p].r)/2; if (mid>=x){ int num=queryr(p+1,x,tag); if (num!=mid) return num; if (o[tag][mid]==false) return num; return queryr(T[p].pr,mid+1,tag); } else return queryr(T[p].pr,x,tag); } Tag query(int p, int l, int r){ if (T[p].l==l&&T[p].r==r) return T[p].can; int mid=(T[p].l+T[p].r)/2; if (mid>=r) return query(p+1,l,r); else if (mid<l) return query(T[p].pr,l,r); else { Tag a=query(p+1,l,mid), b=query(T[p].pr,mid+1,r); return mixed(a,b,mid); } } int main(){ n=read(); int rt=build(1,n); scanf("\n%s",s+1); while (s[1]!='E'){ int dx1=read()-1, dy1=read(), dx2=read()-1, dy2=read(); if (dy1>dy2) swap(dy1,dy2), swap(dx1,dx2); if (s[1]=='O'){ if (dx1!=dx2) modify1(rt,dy1,1); else { o[dx1][dy1]=true; modify0(rt,dy1); } } if (s[1]=='C'){ if (dx1!=dx2) modify1(rt,dy1,0); else{ o[dx1][dy1]=false; modify0(rt,dy1); } } if (s[1]=='A'){ dy1=queryl(rt,dy1,dx1); dy2=queryr(rt,dy2,dx2); Tag num=query(rt,dy1,dy2); if (num.o[dx1][dx2]==true) printf("Y\n"); else printf("N\n"); } scanf("\n%s",s+1); } return 0; }