题目大意:给定一张2*n的网格图,多次改变某条边是否可用,多次查询某两个点是否联通
多(yi)年前的我看到这题的第一反应是:这题尼玛能做?
两个点之间的路径可能是这样的:
也可能是这样的:
甚至可能是这样的:
这题能写?
这题其实好写爆了
我们首先忽略第三种情况,假设所有对答案有贡献的边都在两个点的中间
那么我们以每一列为一个叶节点建立线段树
线段树的每个节点开一个二维数组a[2][2]
其中 a[x][y]记录当前区间的左端点的第x行和右端点的第y行是否联通
那么合并如下:
例如,a[0][0]有上图两种走法
其中左侧灰色框代表线段树的左区间,右侧灰色框代表线段树的右节点
其余三个同理
那么查询就直接去线段树上查询就行了。(暂且无视两边的点对答案的影响)
修改分两种:
如果修改的是一条竖着的边 那么就直接修改叶节点然后向上更新即可
预先开一个数组储存所有横着的边,如果修改的是一条横着的边那么直接修改这个数组的相应位置,然后找到被这条边分开的线段树节点,从该节点开始向上更新即可
那么这题就做完了。。。。等等
这样的情况如何处理?
其实很简单 从左边的点一直向左走 从右面的点一直向右走 走到两边最远的地方 这样对答案有贡献的所有边就都在这两个点中间了
这个用线段树就可以完成
大半夜写的乱七八糟一通乱改结果直接1A这你敢信?
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
struct abcd{
bool a[2][2];
abcd(bool _=false)
{
a[0][0]=a[1][1]=true;
a[0][1]=a[1][0]=_;
}
bool* operator [] (int x)
{
return a[x];
}
friend abcd Merge(bool sta[2],abcd x,abcd y)
{
abcd re;
re[0][0]=(x[0][0]&sta[0]&y[0][0])|(x[0][1]&sta[1]&y[1][0]);
re[1][1]=(x[1][1]&sta[1]&y[1][1])|(x[1][0]&sta[0]&y[0][1]);
re[0][1]=(x[0][0]&sta[0]&y[0][1])|(x[0][1]&sta[1]&y[1][1]);
re[1][0]=(x[1][1]&sta[1]&y[1][0])|(x[1][0]&sta[0]&y[0][0]);
return re;
}
};
int n;
bool a[M][2];
struct Segtree{
Segtree *ls,*rs;
abcd status;
Segtree():ls(0x0),rs(0x0) {}
#define Push_Up(); status=Merge(a[mid],ls->status,rs->status);
void Build_Tree(int x,int y)
{
int mid=x+y>>1;
if(x==y) return ;
(ls=new Segtree)->Build_Tree(x,mid);
(rs=new Segtree)->Build_Tree(mid+1,y);
Push_Up();
}
void Modify(int x,int y,int pos,int flag)
{
int mid=x+y>>1;
if(x==y)
{
new (&status)abcd(flag);
return ;
}
if(pos<=mid)
ls->Modify(x,mid,pos,flag);
else
rs->Modify(mid+1,y,pos,flag);
Push_Up();
}
void Refresh(int x,int y,int pos)
{
int mid=x+y>>1;
if(pos==mid)
{
Push_Up();
return ;
}
if(pos<mid)
ls->Refresh(x,mid,pos);
else
rs->Refresh(mid+1,y,pos);
Push_Up();
}
void _Get_Left(int x,int y,int &pos,abcd &sta,bool flag)
{
int mid=x+y>>1;
if(x==y) return ;
abcd temp=Merge(a[y],rs->status,sta);
if( temp[0][flag] || temp[1][flag] )
pos=mid+1,sta=temp,ls->_Get_Left(x,mid,pos,sta,flag);
else
rs->_Get_Left(mid+1,y,pos,sta,flag);
}
void Get_Left(int x,int y,int &pos,abcd &sta,bool flag)
{
int mid=x+y>>1;
if(x==y) return ;
if(pos<=mid)
ls->Get_Left(x,mid,pos,sta,flag);
else
{
rs->Get_Left(mid+1,y,pos,sta,flag);
if(pos!=mid+1) return ;
abcd temp=Merge(a[mid],ls->status,sta);
if( temp[0][flag] || temp[1][flag] )
pos=x,sta=temp;
else
ls->_Get_Left(x,mid,pos,sta,flag);
}
}
void _Get_Right(int x,int y,int &pos,abcd &sta,bool flag)
{
int mid=x+y>>1;
if(x==y) return ;
abcd temp=Merge(a[x-1],sta,ls->status);
if( temp[flag][0] || temp[flag][1] )
pos=mid,sta=temp,rs->_Get_Right(mid+1,y,pos,sta,flag);
else
ls->_Get_Right(x,mid,pos,sta,flag);
}
void Get_Right(int x,int y,int &pos,abcd &sta,bool flag)
{
int mid=x+y>>1;
if(x==y) return ;
if(pos>mid)
rs->Get_Right(mid+1,y,pos,sta,flag);
else
{
ls->Get_Right(x,mid,pos,sta,flag);
if(pos!=mid) return ;
abcd temp=Merge(a[mid],sta,rs->status);
if( temp[flag][0] || temp[flag][1] )
pos=y,sta=temp;
else
rs->_Get_Right(mid+1,y,pos,sta,flag);
}
}
abcd Get_Ans(int x,int y,int l,int r)
{
int mid=x+y>>1;
if(x==l&&y==r)
return status;
if(r<=mid)
return ls->Get_Ans(x,mid,l,r);
if(l>mid)
return rs->Get_Ans(mid+1,y,l,r);
return Merge(a[mid],ls->Get_Ans(x,mid,l,mid),rs->Get_Ans(mid+1,y,mid+1,r));
}
}*tree=new Segtree;
void Modify(int x1,int y1,int x2,int y2,bool flag)
{
if(x1==x2)
{
if(y1>y2) swap(y1,y2);
a[y1][x1-1]=flag;
tree->Refresh(1,n,y1);
return ;
}
tree->Modify(1,n,y1,flag);
}
void Query(int x1,int y1,int x2,int y2)
{
if(y1>y2) swap(x1,x2),swap(y1,y2);
abcd temp(false);
tree->Get_Left(1,n,y1,temp,x1-1);
x1=temp[0][x1-1]?1:2;
new (&temp)abcd(false);
tree->Get_Right(1,n,y2,temp,x2-1);
x2=temp[x2-1][0]?1:2;
temp=tree->Get_Ans(1,n,y1,y2);
puts(temp[x1-1][x2-1]?"Y":"N");
}
int main()
{
int x1,y1,x2,y2;
char p[10];
cin>>n;
tree->Build_Tree(1,n);
while(1)
{
scanf("%s",p);
if(p[0]=='C')
scanf("%d%d%d%d",&x1,&y1,&x2,&y2),Modify(x1,y1,x2,y2,false);
if(p[0]=='O')
scanf("%d%d%d%d",&x1,&y1,&x2,&y2),Modify(x1,y1,x2,y2,true);
if(p[0]=='A')
scanf("%d%d%d%d",&x1,&y1,&x2,&y2),Query(x1,y1,x2,y2);
if(p[0]=='E')
break;
}
return 0;
}