[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

2
Open 1 1 1 2
Open 1 2 2 2
Ask 1 1 2 2
Ask 2 1 2 2
Exit

Sample Output

Y
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;
}

posted @ 2018-02-23 21:37  Vanisher  阅读(196)  评论(0编辑  收藏  举报