题目大意:给定一张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; }
BZOJ 1018 SHOI2008 堵塞的交通traffic 线段树
原文地址:http://blog.csdn.net/popoqqq/article/details/44116729