Description
有一天,由于某种穿越现象作用,你来到了传说中的小人国。小人国的布局非常奇特,整个国家的交通系统可
以被看成是一个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;
Input
第一行只有一个整数C,表示网格的列数。接下来若干行,每行为一条交通信息,以单独的一行“Exit”作为结束。我们假设在一开始所有的道路都是堵塞的。我们保证 C小于等于100000,信息条数小于等于100000。
Output
对于每个查询,输出一个“Y”或“N”。
Sample Input
2
Open 1 1 1 2
Open 1 2 2 2
Ask 1 1 2 2
Ask 2 1 2 2
Exit
Sample Output
Y
N
解题思路:
又是线段树的神奇应用:维护2*n网格图的连通性。
先看官方题解:
假设询问(r1,1)到(r2,2)(c2>=c1)的连通性,我们对最复杂的连通方式进行分析:
将路线分成3个部分,很容易发现,路线只有几种可能:
1.从(r1,1)直接一直向右、上、下走直接到(r2,2)
2.先从(r1,1)到(r1,2),再从(r1,2)直接一直向右、上、下走直接到(r2,2)
3.从(r1,1)直接一直向右、上、下走直接到(r2,1),再从(r2,1)到(r2,2)
4.先从(r1,1)到(r1,2),再从(r1,2)直接一直向右、上、下走直接到(r2,1) ,再从(r2,1)到(r2,2)
其中,(r1,1)到(r1,2)的方法只能是一直向左走到某个地方,然后想下,再一直向右走到(r1,2)
同理,(r2,1)到(r2,2)的方法只能是一直向右走到某个地方,然后想下,再一直向左走到(r2,2)
于是我们只需要能够快速得到如下数据便可以判断(r1,1),(r2,2)是否连通:
1.(r1,1)到(r1,2),只能先左走一段,再向下,再右走一段是否有路
2.(r2,1)到(r2,2),只能先右走一段,再向下,再左走一段是否有路
3.从(r1,1)到(r2,1),从(r1,1)到(r2,2),从(r1,2)到(r2,1),从(r1,2)到(r2,2),只能右上下走,是否有路
而这3个数据都可以用线段树维护,具体的维护方法请自行思考。
我说一下具体的维护方法:
线段树一个节点(l,r)要维护题解中所说的共六种连通性,且只能经过区间(l,r)内的点,查询时要查(1,c1),(c1,c2),(c2,n)三个区间的联通情况,再作讨论得到答案。
具体细节还是要看代码,比较好懂。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=100005;
const int dx[3]={-1,0,1};
const int dy[3]={0,1,0};
struct node{bool s[2],x[2],v[2];}tr[N<<2];
int n,r1,r2,c1,c2;
bool a[N][2][2];
void build(int k,int l,int r)
{
if(l==r){tr[k].x[0]=tr[k].x[1]=1;return;}
int mid=l+r>>1;
build(k<<1,l,mid),build(k<<1|1,mid+1,r);
}
void update(node &u,node l,node r,int mid)
{
u.s[0]=(l.s[0])||(l.x[0]&&a[mid][0][0]&&r.s[0]&&a[mid][1][0]&&l.x[1]);//左上左下
u.s[1]=(r.s[1])||(r.x[0]&&a[mid][0][0]&&l.s[1]&&a[mid][1][0]&&r.x[1]);//右上右下
u.x[0]=(l.x[0]&&a[mid][0][0]&&r.x[0])||(l.v[0]&&a[mid][1][0]&&r.v[1]);//左上右上
u.x[1]=(l.x[1]&&a[mid][1][0]&&r.x[1])||(l.v[1]&&a[mid][0][0]&&r.v[0]);//左下右下
u.v[0]=(l.x[0]&&a[mid][0][0]&&r.v[0])||(l.v[0]&&a[mid][1][0]&&r.x[1]);//左上右下
u.v[1]=(l.x[1]&&a[mid][1][0]&&r.v[1])||(l.v[1]&&a[mid][0][0]&&r.x[0]);//左下右上
}
void modify(int k,int l,int r,int pos)
{
if(l==r)
{
tr[k].s[0]=tr[k].s[1]=tr[k].v[0]=tr[k].v[1]=a[pos][0][1];
tr[k].x[0]=tr[k].x[1]=1;
return;
}
int mid=l+r>>1;
if(pos<=mid)modify(k<<1,l,mid,pos);
else modify(k<<1|1,mid+1,r,pos);
update(tr[k],tr[k<<1],tr[k<<1|1],mid);
}
void change(int f)
{
if(r1>r2)swap(r1,r2),swap(c1,c2);
int i;
for(i=0;i<3;i++)
if(r1+dy[i]==r2&&c1+dx[i]==c2)break;
if(i==0)a[c2][r2][0]=f,modify(1,1,n,c2);
else if(i==1)a[c2][0][1]=f,modify(1,1,n,c2);
else a[c1][r1][0]=f,modify(1,1,n,c1);
}
node query(int k,int l,int r,int x,int y)
{
if(l==x&&r==y)return tr[k];
int mid=l+r>>1;
if(y<=mid)return query(k<<1,l,mid,x,y);
else if(x>mid)return query(k<<1|1,mid+1,r,x,y);
node a=query(k<<1,l,mid,x,mid),b=query(k<<1|1,mid+1,r,mid+1,y),res;
update(res,a,b,mid);
return res;
}
void get_ans()
{
if(c1>c2)swap(r1,r2),swap(c1,c2);
node l=query(1,1,n,1,c1),mid=query(1,1,n,c1,c2),r=query(1,1,n,c2,n);
if(r1==r2)
{
if(r1==0)
{
if(mid.x[0]||(l.s[1]&&mid.v[1])||(mid.v[0]&&r.s[0])||(l.s[1]&&mid.x[1]&&r.s[0]))puts("Y");
else puts("N");
}
else
{
if(mid.x[1]||(l.s[1]&&mid.v[0])||(mid.v[1]&&r.s[0])||(l.s[1]&&mid.x[0]&&r.s[0]))puts("Y");
else puts("N");
}
}
else
{
if(r1==0)
{
if(mid.v[0]||(l.s[1]&&mid.x[1])||(mid.x[0]&&r.s[0])||(l.s[1]&&mid.v[1]&&r.s[0]))puts("Y");
else puts("N");
}
else
{
if(mid.v[1]||(l.s[1]&&mid.x[0])||(mid.x[1]&&r.s[0])||(l.s[1]&&mid.v[0]&&r.s[0]))puts("Y");
else puts("N");
}
}
}
int main()
{
//freopen("lx.in","r",stdin);
n=getint();build(1,1,n);
char s[5];
while(scanf("%s",s))
{
if(s[0]=='E')break;
r1=getint()-1,c1=getint(),r2=getint()-1,c2=getint();
if(s[0]=='O')change(1);
else if(s[0]=='C')change(0);
else get_ans();
}
return 0;
}