题意: 有一个两行C列的城市网格。每个城市用(r,c)表示,即第r行的第c列。一共有3*C-2条道路,用两端的城市坐标(r1,c1)-(r2,c2)表示。要求支持3种操作:打开某条边,关闭某条边,检查某两个点是否连通(即:只通过打开的边互相可达)。初始时所有边关闭。
解法: 如果没有关闭边的操作,那么只需要并查集即可,但是因为需要删边,使得并查集无法使用,但是路径压缩的思想,在这题仍然还是可用的。把C列分成C/size个长度为size的块,每次对边操作时,重新计算边所属块的连通性(即块最左边的两个点与块最右边的两个点是否可达),然后询问时,对于询问点所属的块,暴力计算该点和该块左右端点的连通性,再通过之前处理的块的信息来计算该点和全图中其他块的连通性,若询问的两个点的访问集合有交集,即说明他们互相可达。注意这里必须是计算点到全图所有块的连通性,想象一下你要去街道的对面,是不是需要先找到斑马线,而斑马线可能距离你的位置很远。还有注意有两个点坐标相同的数据,这种直接就是Y。
代码细节真多。
/* Created Time: Wednesday, October 30, 2013 AM09:01:53 CST */
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
const int M = 100100;
int lx,ly,rx,ry,n;
int b_size,b_num,g[2][M],block[555][2][2],tim,vis[2][M];
void init() {
memset(g,0,sizeof(g));
b_size = int(sqrt(double(n)));
b_num = n/b_size + (n%b_size!=0);
memset(block,0,sizeof(block));
memset(vis,0,sizeof(vis));
tim = 0;
}
void get(int x,int y) {
int bb = y/b_size;
int ly = bb*b_size;
int ry = min(ly+b_size,n)-1;
tim ++;
vis[0][ly] = tim;
if (g[0][ly]&4) vis[1][ly] = tim;
for (int i = ly+1; i<=ry; i ++) {
if (vis[0][i-1]==tim && (g[0][i]&8)) {
vis[0][i] = tim;
if (g[0][i]&4) vis[1][i] = tim;
}
if (vis[1][i-1]==tim && (g[1][i]&8)) {
vis[1][i] = tim;
if (g[1][i]&1) vis[0][i] = tim;
}
}
block[bb][0][0] = (vis[0][ry]==tim);
block[bb][0][1] = (vis[1][ry]==tim);
tim ++;
vis[1][ly] = tim;
if (g[1][ly]&1) vis[0][ly] = tim;
for (int i = ly+1; i<=ry; i ++) {
if (vis[0][i-1]==tim && (g[0][i]&8)) {
vis[0][i] = tim;
if (g[0][i]&4) vis[1][i] = tim;
}
if (vis[1][i-1]==tim && (g[1][i]&8)) {
vis[1][i] = tim;
if (g[1][i]&1) vis[0][i] = tim;
}
}
block[bb][1][0] = (vis[0][ry]==tim);
block[bb][1][1] = (vis[1][ry]==tim);
}
void update() {
if (lx==rx) {
if (ly>ry) swap(ly,ry);
g[lx][ly] ^= 2;
g[rx][ry] ^= 8;
} else {
if (lx>rx) swap(lx,rx);
g[lx][ly] ^= 4;
g[rx][ry] ^= 1;
}
get(lx,ly);
get(rx,ry);
}
bool flag;
void mark(int x,int y) {
if (vis[x][y]==tim-1) flag = true;
vis[x][y] = tim;
}
bool move(int x,int y) {
flag = false;
tim ++;
vis[x][y] = tim;
if (x==0 && (g[x][y]&4)) mark(!x,y);
if (x==1 && (g[x][y]&1)) mark(!x,y);
int ty,bb;
bb = y/b_size;
ty = min((bb+1)*b_size,n)-1;
for (int i = y+1; i <= ty; i ++) {
if (vis[0][i-1]==tim && (g[0][i]&8)) {
mark(0,i);
if (g[0][i]&4) mark(1,i);
}
if (vis[1][i-1]==tim && (g[1][i]&8)) {
mark(1,i);
if (g[1][i]&1) mark(0,i);
}
}
for (int i = bb+1; i < b_num; i ++) {
int py = i*b_size-1;
if (vis[0][py]==tim && (g[0][py]&2)) {
mark(0,py+1);
if (g[0][py+1]&4) mark(1,py+1);
}
if (vis[1][py]==tim && (g[1][py]&2)) {
mark(1,py+1);
if (g[1][py+1]&1) mark(0,py+1);
}
int ty = min(py+b_size,n-1);
if (vis[0][py+1]==tim) {
if (block[i][0][0]) mark(0,ty);
if (block[i][0][1]) mark(1,ty);
}
if (vis[1][py+1]==tim) {
if (block[i][1][0]) mark(0,ty);
if (block[i][1][1]) mark(1,ty);
}
}
ty = bb*b_size;
for (int i = y-1; i >= ty; i --) {
if (vis[0][i+1]==tim && (g[0][i]&2)) {
mark(0,i);
if (g[0][i]&4) mark(1,i);
}
if (vis[1][i+1]==tim && (g[1][i]&2)) {
mark(1,i);
if (g[1][i]&1) mark(0,i);
}
}
for (int i = bb-1; i >= 0; i --) {
int py = (i+1)*b_size-1;
if (vis[0][py+1]==tim && (g[0][py]&2)) {
mark(0,py);
if (g[0][py]&4) mark(1,py);
}
if (vis[1][py+1]==tim && (g[1][py]&2)) {
mark(1,py);
if (g[1][py]&1) mark(0,py);
}
int ty = i*b_size;
if (vis[0][py]==tim) {
if (block[i][0][0]) mark(0,ty);
if (block[i][1][0]) mark(1,ty);
}
if (vis[1][py]==tim) {
if (block[i][0][1]) mark(0,ty);
if (block[i][1][1]) mark(1,ty);
}
}
return flag;
}
bool ask() {
if (lx==rx && ly==ry) return true;
move(lx,ly);
return move(rx,ry);
}
int main() {
int cas;
char s[22];
scanf("%d",&cas);
while (cas--) {
scanf("%d",&n);
init();
while (~scanf("%s",s)) {
if (s[0]=='E') break;
scanf("%d%d%d%d",&lx,&ly,&rx,&ry);
lx--,ly--,rx--,ry--;
if (s[0]=='A')
puts(ask()?"Y":"N");
else
update();
}
}
return 0;
}