线段树三连。
这是一道让人误解为水题的线段树题。
实则让我想骂出题人出了这么道大毒瘤。
题意:维护2*n的网格区域中点的连通性。
题解:线段树维护连通性。
把上下两个城市看作线段树中的一个点
合并两个区间时,只看这两个区间的左,右端点,更新合并区间的连通性。这个很好想,不过实现起来…嘿嘿嘿
记录横向的线段,用于合并时判断。由于修改都是单条路修改,记录起来也不太难。
总之就是要多画图,把两点连通性的所有情况给画出来。
可以见这里,讲得更清楚。
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 100001;
int n;
inline int read(){
int k = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){k = k*10 + ch - '0'; ch = getchar();}
return k * f;
}
struct Segment_Tree{
#define mid ((l + r) >> 1)
bool r1[MAXN], r2[MAXN]; //上下公路,向右
struct Node{
int l, r;
bool l1r1, l1r2, l1l2, l2r1, l2r2, r1r2;
}t[MAXN << 2];
inline void Pushup(Node *u, Node ls, Node rs){
u->l = ls.l, u->r = rs.r;
u->l1l2 = ls.l1l2 || (ls.l1r1 && r1[ls.r] && rs.l1l2 && r2[ls.r] && ls.l2r2);
u->r1r2 = rs.r1r2 || (rs.l1r1 && r1[ls.r] && ls.r1r2 && r2[ls.r] && rs.l2r2);
u->l1r1 = (ls.l1r1 && r1[ls.r] && rs.l1r1) || (ls.l1r2 && r2[ls.r] && rs.l2r1);
u->l2r2 = (ls.l2r1 && r1[ls.r] && rs.l1r2) || (ls.l2r2 && r2[ls.r] && rs.l2r2);
u->l1r2 = (ls.l1r1 && r1[ls.r] && rs.l1r2) || (ls.l1r2 && r2[ls.r] && rs.l2r2);
u->l2r1 = (ls.l2r1 && r1[ls.r] && rs.l1r1) || (ls.l2r2 && r2[ls.r] && rs.l2r1);
}
inline void Build(int u, int l, int r){
if(l == r){t[u].l = t[u].r = l; t[u].l1r1 = t[u].l2r2 = true; return;}
Build(u << 1, l, mid), Build(u << 1 | 1, mid + 1, r);
Pushup(&t[u], t[u << 1], t[u << 1 | 1]);
}
inline void Modify1(int u, int l, int r, int x, bool opt){ //处理竖着的
if(l == r){t[u].l1l2 = t[u].r1r2 = t[u].l1r2 = t[u].l2r1 = opt; return;}
if(x <= mid) Modify1(u << 1, l, mid, x, opt);
if(x > mid) Modify1(u << 1 | 1, mid + 1, r, x, opt);
Pushup(&t[u], t[u << 1], t[u << 1 | 1]);
}
inline void Modify2(int u, int l, int r, int x, bool y, bool opt){ //处理横着的
if(x == mid) (y == 0) ? r1[x] = opt : r2[x] = opt;
else if(x < mid) Modify2(u << 1, l, mid, x, y, opt);
else if(x > mid) Modify2(u << 1 | 1, mid + 1, r, x, y, opt);
Pushup(&t[u], t[u << 1], t[u << 1 | 1]);
}
inline Node Query(int u, int l, int r, int L, int R){ //询问c1, c2之间区间的联通性
if(l >= L && r <= R) return t[u];
if(R <= mid) return Query(u << 1, l, mid, L, R);
if(L > mid) return Query(u << 1 | 1, mid + 1, r, L, R);
Node Tmp1 = Query(u << 1, l, mid, L, mid), Temp;
Node Tmp2 = Query(u << 1 | 1, mid + 1, r, mid + 1, R);
Pushup(&Temp, Tmp1, Tmp2); return Temp;
}
inline void Ask(int ra, int ca, int rb, int cb){
Node L = Query(1, 1, n, 1, ca);
Node M = Query(1, 1, n, ca, cb);
Node R = Query(1, 1, n, cb, n);
bool b1 = false, b2 = false, b3 = false, b4 = false;
if(ra == 0 && rb == 0){
b1 = M.l1r1;
b2 = L.r1r2 && M.l2r1;
b3 = R.l1l2 && M.l1r2;
b4 = L.r1r2 && M.l2r2 && R.l1l2;
} else if(ra == 0 && rb == 1){
b1 = M.l1r2;
b2 = L.r1r2 && M.l2r2;
b3 = R.l1l2 && M.l1r1;
b4 = L.r1r2 && M.l2r1 && R.l1l2;
} else if(ra == 1 && rb == 0){
b1 = M.l2r1;
b2 = L.r1r2 && M.l1r1;
b3 = R.l1l2 && M.l2r2;
b4 = L.r1r2 && M.l1r2 && R.l1l2;
} else if(ra == 1 && rb == 1){
b1 = M.l2r2;
b2 = L.r1r2 && M.l1r2;
b3 = R.l1l2 && M.l2r1;
b4 = L.r1r2 && M.l1r1 && R.l1l2;
}
if(b1 || b2 || b3 || b4){
puts("Y");
} else{
puts("N");
}
return;
}
#undef mid
}T;
int main(){
freopen("in.txt", "r", stdin);
n = read(); char opt[10];
T.Build(1, 1, n);
while(1){
scanf("%s", opt);
if(opt[0] == 'E') break;
int ra = read() - 1, ca = read(), rb = read() - 1, cb = read();
if(ca > cb) swap(ra, rb), swap(ca, cb);
if(opt[0] == 'O' || opt[0] == 'C'){
int w = (opt[0] == 'O');
if(ra == rb){ //横着的
T.Modify2(1, 1, n, ca, ra, w);
} else{ //竖着的
T.Modify1(1, 1, n, ca, w);
}
}
else{
T.Ask(ra, ca, rb, cb);
}
}
return 0;
}