这是一道毒瘤题
只要线段树维护一个矩形的四个点的连通性即可
合并时请想清楚,要大讨论一番
询问有可能存在跨区间的联通情况,只要把询问的区间分成[1,l],[l,r],[r,n]再大讨论一番即可
如果你不想讨论或者讨论出错,你可以使用并查集,每次开并查集更新,这样就不用大讨论一番了,但是会慢,时间几乎是两倍。。。
像我这种不会讨论的蒟蒻想到了后果断用并查集
自我感觉代码还是比较短的
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define ZSYbeatME 666
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(4e6 + 10), INF(2e9);
IL ll Read(){
char c = '%'; ll x = 0, z = 1;
for(; c > '9' || c < '0'; c = getchar()) if(c == '-') z = -1;
for(; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
return x * z;
}
int n, gg;
struct Data{
bool ab, ac, ad, bc, bd, cd;
IL void Init(){ ab = ac = ad = bc = bd = cd = 0; }
} t[_], f[_];
int fa[4];
IL int Find(RG int x){ return fa[x] == x ? x : fa[x] = Find(fa[x]); }
IL void Link(RG int x, RG int y){ if(Find(x) != Find(y)) fa[Find(x)] = Find(y); }
IL bool OK(RG int x, RG int y){ return Find(x) == Find(y); }
IL void Update(RG Data &A){
for(RG int i = 0; i < 4; i++) fa[i] = i;
if(A.ab) Link(0, 1); if(A.ac) Link(0, 2);
if(A.ad) Link(0, 3); if(A.bc) Link(1, 2);
if(A.bd) Link(1, 3); if(A.cd) Link(2, 3);
A.ab = OK(0, 1); A.ac = OK(0, 2);
A.ad = OK(0, 3); A.bc = OK(1, 2);
A.bd = OK(1, 3); A.cd = OK(2, 3);
}
IL Data Merge(RG Data A, RG Data B){
RG Data C;
C.ab = A.ab | (A.ad & A.bc & B.ab);
C.cd = B.cd | (B.ad & B.bc & A.cd);
C.ac = (A.ac & B.bc) | (A.ad & B.ac);
C.ad = (A.ad & B.ad) | (A.ac & B.bd);
C.bc = (A.bc & B.bc) | (A.bd & B.ac);
C.bd = (A.bd & B.ad) | (A.bc & B.bd);
Update(C);
return C;
}
IL void Modify(RG int x, RG int l, RG int r, RG int id, RG int d, RG bool v){
if(id < l || id > r) return;
if(l == r){
if(d == 0) f[x].ab = v;
else if(d == 1) f[x].cd = v;
else if(d == 2) f[x].ad = v;
else f[x].bc = v;
t[x] = f[x]; Update(t[x]);
return;
}
RG int mid = (l + r) >> 1;
if(id <= mid) Modify(x << 1, l, mid, id, d, v);
else Modify(x << 1 | 1, mid + 1, r, id, d, v);
t[x] = Merge(t[x << 1], t[x << 1 | 1]);
}
IL Data Query(RG int x, RG int l, RG int r, RG int L, RG int R){
RG Data ans; ans.Init();
if(L > R) return ans;
if(L <= l && R >= r) return t[x];
RG int mid = (l + r) >> 1;
if(R <= mid) return Query(x << 1, l, mid, L, R);
if(L > mid) return Query(x << 1 | 1, mid + 1, r, L, R);
ans = Merge(Query(x << 1, l, mid, L, R), Query(x << 1 | 1, mid + 1, r, L, R));
return ans;
}
IL bool Calc(RG int a, RG int b, RG int c, RG int d){
RG Data A = Query(1, 1, n, 1, b - 1), B, C = Query(1, 1, n, d, n);
if(b == d) return A.cd | C.ab;
B = Query(1, 1, n, b, d - 1);
B.ab |= A.cd; B.cd |= C.ab; Update(B);
if(a == 1 && c == 2) return B.ac;
if(a == 1 && c == 1) return B.ad;
if(a == 2 && c == 1) return B.bd;
if(a == 2 && c == 2) return B.bc;
}
int main(RG int argc, RG char *argv[]){
n = Read() - 1; RG char op[10]; RG int a, b, c, d;
while(ZSYbeatME){
scanf(" %s", op); if(op[0] == 'E') break;
a = Read(); b = Read(); c = Read(); d = Read();
if(b > d) swap(a, c), swap(b, d);
if(op[0] == 'A') puts(Calc(a, b, c, d) ? "Y" : "N");
else{
RG int opt = op[0] == 'O';
if(b == d) Modify(1, 1, n, b, 0, opt), Modify(1, 1, n, b - 1, 1, opt);
else Modify(1, 1, n, b, a + 1, opt);
}
}
return 0;
}