[BZOJ1018][SHOI2008]堵塞的交通traffic

[BZOJ1018][SHOI2008]堵塞的交通traffic

试题描述

有一天,由于某种穿越现象作用,你来到了传说中的小人国。小人国的布局非常奇特,整个国家的交通系统可以被看成是一个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;

输入

第一行只有一个整数C,表示网格的列数。接下来若干行,每行为一条交通信息,以单独的一行“Exit”作为结束。我们假设在一开始所有的道路都是堵塞的。 对30%测试数据,我们保证C小于等于1000,信息条数小于等于1000; 对100%测试数据,我们保证 C小于等于100000,信息条数小于等于100000。

输出

对于每个查询,输出一个“Y”或“N”。

输入示例

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

输出示例

Y
N

数据规模及约定

见“输入

题解

用线段树维护连通性。每个区间维护 左上右上、左上右下、左上左下、左下右上、左下右下、右上右下 的连通性,合并两个区间时分类讨论一下怎么从起点走到目标位置。

以下代码 0, 1, 2, 3 分别表示 左上、右上、左下、右下。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define maxn 100010
#define maxlog 50
int n, maxo;
char tp[10];
bool Oc[2][maxn], Or[maxn];

bool con[4][4][maxn<<2];
void combine(int o, int lc, int rc, int M) {
	con[0][1][o] = (con[0][1][lc] & Oc[0][M] & con[0][1][rc]) | (con[0][3][lc] & Oc[1][M] & con[1][2][rc]);
	con[0][3][o] = (con[0][1][lc] & Oc[0][M] & con[0][3][rc]) | (con[0][3][lc] & Oc[1][M] & con[2][3][rc]);
	con[0][2][o] = con[0][2][lc] | (con[0][1][lc] & Oc[0][M] & con[0][2][rc] & Oc[1][M] & con[2][3][lc]);
	con[1][2][o] = (con[1][2][lc] & Oc[0][M] & con[0][1][rc]) | (con[2][3][lc] & Oc[1][M] & con[1][2][rc]);
	con[1][3][o] = con[1][3][rc] | (con[0][1][rc] & Oc[0][M] & con[1][3][lc] & Oc[1][M] & con[2][3][rc]);
	con[2][3][o] = (con[1][2][lc] & Oc[0][M] & con[0][3][rc]) | (con[2][3][lc] & Oc[1][M] & con[2][3][rc]);
	return ;
}
void build(int L, int R, int o) {
	maxo = max(maxo, o);
	if(L == R) con[0][1][o] = con[2][3][o] = 1;
	else {
		int M = L + R >> 1, lc = o << 1, rc = lc | 1;
		build(L, M, lc); build(M+1, R, rc);
		combine(o, lc, rc, M);
	}
	return ;
}
void update(int tp, int L, int R, int o, int r, int c, int v) {
	if(L == R) {
		if(tp) con[0][2][o] = con[1][3][o] = con[0][3][o] = con[1][2][o] = Or[c] = v;
		else Oc[r][c] = v;
		return ;
	}
	int M = L + R >> 1, lc = o << 1, rc = lc | 1;
	if(c <= M) update(tp, L, M, lc, r, c, v);
	else update(tp, M+1, R, rc, r, c, v);
	combine(o, lc, rc, M);
	return ;
}
int cnt, ql, qr, que[maxlog], quer[maxlog];
void Query(int L, int R, int o) {
	if(ql <= L && R <= qr) {
		que[++cnt] = o; quer[cnt] = R;
		return ;
	}
	int M = L + R >> 1, lc = o << 1, rc = lc | 1;
	if(ql <= M) Query(L, M, lc);
	if(qr > M) Query(M+1, R, rc);
	return ;
}
bool query(int r1, int c1, int r2, int c2) {
	if(c1 > c2) swap(r1, r2), swap(c1, c2);
	
	bool flag[4]; memset(flag, 0, sizeof(flag));
	cnt = 0; ql = 1; qr = c1;
	Query(1, n, 1);
	for(int i = 0; i < 4; i++)
		for(int j = i+1; j < 4; j++) con[i][j][0] = con[i][j][que[1]];
	for(int k = 2; k <= cnt; k++) {
		combine(maxo + 1, 0, que[k], quer[k-1]);
		for(int i = 0; i < 4; i++)
			for(int j = i+1; j < 4; j++) con[i][j][0] = con[i][j][maxo+1];
	}
	if(con[1][3][0]) flag[0] = flag[2] = 1;
	else {
		if(!r1) flag[0] = 1;
		else flag[2] = 1;
	}
	cnt = 0; ql = c2; qr = n;
	Query(1, n, 1);
	for(int i = 0; i < 4; i++)
		for(int j = i+1; j < 4; j++) con[i][j][0] = con[i][j][que[1]];
	for(int k = 2; k <= cnt; k++) {
		combine(maxo + 1, 0, que[k], quer[k-1]);
		for(int i = 0; i < 4; i++)
			for(int j = i+1; j < 4; j++) con[i][j][0] = con[i][j][maxo+1];
	}
	if(con[0][2][0]) flag[1] = flag[3] = 1;
	else {
		if(!r2) flag[1] = 1;
		else flag[3] = 1;
	}
//	printf("%d %d %d %d\n", r1, c1, r2, c2);
//	printf("%d %d %d %d\n", flag[0], flag[1], flag[2], flag[3]);
	
	cnt = 0; ql = c1; qr = c2;
	Query(1, n, 1);
	for(int i = 0; i < 4; i++)
		for(int j = i+1; j < 4; j++) con[i][j][0] = con[i][j][que[1]];
	for(int k = 2; k <= cnt; k++) {
		combine(maxo + 1, 0, que[k], quer[k-1]);
		for(int i = 0; i < 4; i++)
			for(int j = i+1; j < 4; j++) con[i][j][0] = con[i][j][maxo+1];
	}
//	printf("%d %d %d %d %d\n", con[0][1][1], con[0][3][1], con[1][2][1], con[1][3][1], con[0][2][1]);
	for(int i = 0; i < 4; i += 2)
		for(int j = 1; j < 4; j += 2) if(flag[i] && flag[j] && con[min(i,j)][max(i,j)][0])
			return 1;
	return 0;
}

int main() {
	scanf("%d", &n);
	build(1, n, 1);
	int top = 0, tot = 0;
	while(scanf("%s", &tp) == 1) {
		if(tp[0] == 'E') break;
		int r1, c1, r2, c2;
		scanf("%d%d%d%d", &r1, &c1, &r2, &c2);
		r1--; r2--;
//		int r1 = read() - 1, c1 = read(), r2 = read() - 1, c2 = read();
		tot++;
		if(tp[0] == 'O') {
			if(r1 == r2) update(0, 1, n, 1, r1, min(c1, c2), 1);
			else update(1, 1, n, 1, r1, c1, 1);
		}
		if(tp[0] == 'C') {
			if(r1 == r2) update(0, 1, n, 1, r1, min(c1, c2), 0);
			else update(1, 1, n, 1, r1, c1, 0);
		}
		if(tp[0] == 'A') {
//			if(++top == 192) printf("%d %d %d %d %d\n", r1, c1, r2, c2, tot);
			if(query(r1, c1, r2, c2)) printf("Y\n");
			else printf("N\n");
		}
	}
	
	return 0;
}

cnbb 我都要调吐了。。。

posted @ 2016-08-24 08:07  xjr01  阅读(162)  评论(0编辑  收藏  举报