这题需要维护连通性,看到有连接删除,很容易直接就想LCT了。然而这题点数20w操作10w,LCT卡常估计过不去。看到这个东西只有两行,考虑能否用魔改后的线性数据结构去维护。我想到了线段树。
考虑如果两个点相连,能有几种情况。有一种是两个点直接经过中间的路径相连,这个满足合并性,很容易维护。然后就是某一个点(或两个点)从两边绕了一下,由上到下或由下到上,然后走中间了路径相连的情况。
(借用官方的一张图)
对于第二种情况,考虑它应该是是什么样子的。注意这张图总共就两行,那么这个东西一定是从上面一行走横着的边到某一个位置,走一条竖着的边,然后再到下面连续走横着的边。
所以,我们对于某一个位置能否到达其对应位置,只需要维护其横向能到达的最远位置,以及这两个位置之间有没有纵向边即可。
确定位置只需要维护横向连通性,然后线段树二分即可。
横向连通性满足合并性,总向边可以用数量求和,均可以用线段树维护。
于是此题得解。
关于实现,我们定义每个区间保存一个Node,其中f[0/1][0/1]表示区间左边的上、下能否到区间右边的上下(0上1下),维护linked[0/1]表示区间(0上1下)是否左右全部联通,同时维护sum表示这个区间纵向边数量的和。
对于每一个位置,维护ver表示是否有纵向边,hor[0/1]表示从位置i有没有到位置i+1的横向边(0上1下)。
合并的话节点直接用左右状态判,和很容易转移。
查询位置的线段树二分,无非就是先向上走再向下走,自行脑补一发即可(不会看代码)。
最终判定的时候用了一下状压,仅能判定上面的点用1,仅能判定下面用2,如果上下联通,则均可判定,用3来表示。
最后上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define debug cout
using namespace std;
const int maxn=1e5+1e2; int l[maxn<<],r[maxn<<],lson[maxn<<],rson[maxn<<],fa[maxn<<];
int linked[maxn<<][],ver[maxn],hor[maxn][];
int sum[maxn<<]; struct Node {
int f[][];
int* operator [] (const int &x) {
return f[x];
}
Node() {
memset(f,,sizeof(f));
}
}ns[maxn<<];
int n,m,cnt; inline Node merge(int* h,Node a,Node b) {
Node ret;
ret.f[][] = ( a[][]&h[]&b[][] ) | ( a[][]&h[]&b[][] );
ret.f[][] = ( a[][]&h[]&b[][] ) | ( a[][]&h[]&b[][] );
ret.f[][] = ( a[][]&h[]&b[][] ) | ( a[][]&h[]&b[][] );
ret.f[][] = ( a[][]&h[]&b[][] ) | ( a[][]&h[]&b[][] );
return ret;
} inline void build(int pos,int ll,int rr) {
l[pos] = ll , r[pos] = rr;
if( ll == rr ) {
ns[pos][][] = ns[pos][][] = ;
linked[pos][] = linked[pos][] = ;
return;
}
const int mid = ( ll + rr ) >> ;
build(lson[pos]=++cnt,ll,mid);
build(rson[pos]=++cnt,mid+,rr);
fa[lson[pos]] = fa[rson[pos]] = pos;
}
inline void update_ver(int pos,int tar,int sta) {
if( tar < l[pos] || r[pos] < tar )
return;
if( l[pos] == r[pos] ) {
sum[pos] = ver[tar] = sta;
ns[pos][][] = ns[pos][][] = sta;
return;
}
const int mid = ( l[pos] + r[pos] ) >> ;
update_ver(lson[pos],tar,sta);
update_ver(rson[pos],tar,sta);
ns[pos] = merge(hor[mid],ns[lson[pos]],ns[rson[pos]]);
sum[pos] = sum[lson[pos]] + sum[rson[pos]]; // remember this
}
inline void update_hor(int pos,int tar,int at,int sta) {
if( tar < l[pos] || r[pos] < tar )
return;
if( l[pos] == r[pos] ) {
hor[tar][at] = sta;
return;
}
const int mid = ( l[pos] + r[pos] ) >> ;
update_hor(lson[pos],tar,at,sta);
update_hor(rson[pos],tar,at,sta);
ns[pos] = merge(hor[mid],ns[lson[pos]],ns[rson[pos]]);
linked[pos][] = linked[lson[pos]][] & hor[mid][] & linked[rson[pos]][],
linked[pos][] = linked[lson[pos]][] & hor[mid][] & linked[rson[pos]][];
}
inline Node querymid(int pos,int ll,int rr) {
if( !pos )
exit();
if( ll <= l[pos] && r[pos] <= rr )
return ns[pos];
const int mid = ( l[pos] + r[pos] ) >> ;
if( rr <= mid )
return querymid(lson[pos],ll,rr);
if( ll > mid )
return querymid(rson[pos],ll,rr);
return merge(hor[mid],querymid(lson[pos],ll,rr),querymid(rson[pos],ll,rr));
}
inline int queryver(int pos,int ll,int rr) {
if( rr < l[pos] || r[pos] < ll )
return ;
if( ll <= l[pos] && r[pos] <= rr )
return sum[pos];
return queryver(lson[pos],ll,rr) + queryver(rson[pos],ll,rr);
}
inline int downleft(int pos,int at) {
if( l[pos] == r[pos] )
return l[pos];
const int mid = ( l[pos] + r[pos] ) >> ;
if( hor[mid][at] && linked[rson[pos]][at] )
return downleft(lson[pos],at);
return downleft(rson[pos],at);
}
inline int leftup(int pos,int at) {
if( pos == )
return ;
if( pos == lson[fa[pos]] )
return leftup(fa[pos],at);
const int fmid = l[pos] - ;
if( hor[fmid][at] ) {
if( linked[lson[fa[pos]]][at] )
return leftup(fa[pos],at);
return downleft(lson[fa[pos]],at);
}
return l[pos];
}
inline int downright(int pos,int at) {
if( l[pos] == r[pos] )
return r[pos];
const int mid = ( l[pos] + r[pos] ) >> ;
if( hor[mid][at] && linked[lson[pos]][at] )
return downright(rson[pos],at);
return downright(lson[pos],at);
}
inline int rightup(int pos,int at) {
if( pos == )
return n;
if( pos == rson[fa[pos]] )
return rightup(fa[pos],at);
const int fmid = r[pos];
if( hor[fmid][at] ) {
if( linked[rson[fa[pos]]][at] )
return rightup(fa[pos],at);
return downright(rson[fa[pos]],at);
}
return r[pos];
}
inline int findpos(int pos,int tar) {
while( l[pos] != r[pos] ) {
const int mid = ( l[pos] + r[pos] ) >> ;
if( tar <= mid )
pos = lson[pos];
else
pos = rson[pos];
}
return pos;
} inline void solve_case(int x,int y,int xx,int yy) {
int sta = y , stb = yy , ans = ;
const int mostl = max( leftup(findpos(,x),) , leftup(findpos(,x),) );
const int mostr = min( rightup(findpos(,xx),) , rightup(findpos(,xx),) );
if( queryver(,mostl,x) )
sta = ;
if( queryver(,xx,mostr) )
stb = ;
Node md = querymid(,x,xx);
for(int i=;i<;i++)
for(int j=;j<;j++)
if( ( sta & (<<i) ) && ( stb & (<<j) ) )
ans |= md[i][j];
puts(ans?"Y":"N");
} char com[];
int x,y,xx,yy; inline void explain() {
int sta = *com == 'O';
if( y == yy )
update_hor(,x,y-,sta);
else if( x == xx ) {
update_ver(,x,sta);
}
} int main() {
scanf("%d",&n);
build(cnt=,,n);
int cc = ;
while( scanf("%s",com) == && *com != 'E' ) {
scanf("%d%d%d%d",&y,&x,&yy,&xx);
if( x > xx )
swap(x,xx) , swap(y,yy);
if( *com == 'A' )
solve_case(x,y,xx,yy);
else
explain();
} return ; }