[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 我都要调吐了。。。