传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1018
之前挖的坑,现在填吧。
之前一眼看觉得是LCT,一看时限 3s ????
n非常大是log级别的,并查集肯定不可行,
貌似时限开大也不能用lct因为不是树?(也许是我弱
那么就滚去膜题解了了。
这题其实是线段树维护连通性的经典问题。
突破点就在于只有两行。
那么我们只要以每一列为一个节点开一个线段树,对于每一个节点开一个结构体来维护这个节点的连通性即可。 那么如何维护呢?
我们开一个数组,h[2][2],记录的就是这个节点的左端点的第0/1行何右端点的第0/1行是否连通。
然后在记录一下这个节点左端点的上下两行(也就是竖着)是否联通和右端点的上下两行是否联通,
还要在线段树维护两个孩子之间的部分是否联通。
合并的话有几种情况,直接连通或者绕一个弯或者绕两个弯
(自幼灵魂画手在此报道!)
修改有两种情况,同一行相邻格子,或者同一列的两个格子,大体也差不多,yy一下就行了,注意时时合并。
询问函数部分就和线段树一样。
但是主函数询问的时候注意有这种情况:
也就是说连通性不一定是在两点之间的,有可能绕到了前面或者后面去,那么我们询问的时候就要问一下前面和后面的情况在做一个整合即可。
至今做过最有趣的题目之一。
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node//维护一个端点的连通性
{
bool lb,rb;//竖
bool h[2][2];//维护从x节点最左端的i行能否到最右端的j行
node()
{
lb=rb=0;
memset(h,0,sizeof(h));
}
};
struct trnode//线段树
{
int l,r;
int lc,rc;
node f;
bool tp,bm;//维护两个孩子之间的部分(mid~mid+1)
}tr[410000];
int trlen;
int build(int l,int r)
{
int t=++trlen;
tr[t].l=l;tr[t].r=r;
tr[t].tp=tr[t].bm=0;
if(l<r)
{
int mid=(l+r)/2;
tr[t].lc=build(l,mid);
tr[t].rc=build(mid+1,r);
}
else tr[t].f.h[0][0]=tr[t].f.h[1][1]=1;
return t;
}
node merg(node a,int tp,int bm,node b)
{
node c;
c.lb=a.lb || (a.h[0][0] && tp && b.lb && bm && a.h[1][1]);//直接连通或者绕一个弯
c.rb=b.rb || (b.h[0][0] && tp && a.rb && bm && b.h[1][1]);
for(int i=0;i<=1;i++)
for(int j=0;j<=1;j++)
{
c.h[i][j] =a.h[i][0] && tp && b.h[0][j];//绕两个弯
c.h[i][j]|=a.h[i][1] && bm && b.h[1][j];
}
return c;
}
void change(int x,int x1,int y1,int x2,int y2,bool b)
{
int lc=tr[x].lc,rc=tr[x].rc;
int mid=(tr[x].l+tr[x].r)/2;
if(x1==x2 && y1==mid)//横着,正好中间
{
if(x1==0) tr[x].tp=b;
else tr[x].bm=b;
tr[x].f=merg(tr[lc].f,tr[x].tp,tr[x].bm,tr[rc].f);
return;
}
if(tr[x].l==tr[x].r)//其他单点
{
tr[x].f.h[0][1]=tr[x].f.h[1][0]=tr[x].f.lb=tr[x].f.rb=b;
return;
}
if(y1<=mid) change(lc,x1,y1,x2,y2,b);
else change(rc,x1,y1,x2,y2,b);
tr[x].f=merg(tr[lc].f,tr[x].tp,tr[x].bm,tr[rc].f);
}
node ask(int x,int l,int r)
{
int lc=tr[x].lc,rc=tr[x].rc;
int mid=(tr[x].l+tr[x].r)/2;
if(tr[x].l==l && tr[x].r==r) return tr[x].f;
if(r<=mid) return ask(lc,l,r);
if(l>mid) return ask(rc,l,r);
return merg(ask(lc,l,mid),tr[x].tp,tr[x].bm,ask(rc,mid+1,r));
}
char ss[20];
int main()
{
int n;scanf("%d",&n);
trlen=0;build(1,n);
while(1)
{
scanf("%s",ss);
if(ss[0]=='E') break;
int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
x1--;x2--;
if(y1>y2) swap(x1,x2),swap(y1,y2);
if(ss[0]=='A')
{
node a,b,c;
a=ask(1,1,y1);b=ask(1,y1,y2);c=ask(1,y2,n);
if(a.rb) b.lb=1;
if(c.lb) b.rb=1;
bool bk=0;
for(int i=0;i<=1;i++)
for(int j=0;j<=1;j++)
if(b.h[i][j])
if( (i==x1 || b.lb)&&(j==x2 || b.rb) )
bk=1;
if(bk) printf("Y\n");
else printf("N\n");
}
if(ss[0]=='O') change(1,x1,y1,x2,y2,1);
if(ss[0]=='C') change(1,x1,y1,x2,y2,0);
}
return 0;
}