BZOJ1018:[SHOI2008]堵塞的交通

浅谈树状数组与线段树:https://www.cnblogs.com/AKMer/p/9946944.html

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1018

我们把第一行和第二行的城市一起处理,对于每一个区间[\(l,r\)]的城市,我们需要维护下面六种关系:

一共六条边,分别用\(bool\)类型的六个变量来表示这六种联通关系是否成立。

然后询问两个城市是否联通,也许他们会绕出区间[\(l,r\)]再绕回来然后联通,所以有四种路径可以走;假设我询问的是一号城市和三号城市,二号城市是一号城市上方/下方的城市,四号城市是三号城市上方/下方的城市,那么这四条路径分别是:

一号---->三号(红色)

一号----》二号---->三号(绿色)

一号---->四号----》三号(蓝色)

一号----》二号---->四号----》三号(灰色)

其中>表示在区间内,》表示绕出去,如图所示:

时间复杂度:\(O(nlong)\)

空间复杂度:\(O(n)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn=1e5+5;

int n;
char s[10];
bool bo[maxn*3];//bo数组里,[1,n-1]存的是第一行的道路,[n,2*n-1]存的是每一列的道路,[2*n,3*n-2]存的是第二行的道路。

int read() {
	int x=0,f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
	return x*f;
}

struct tree_node {
	bool a1,a2,a3,a4,a5,a6;
};

struct segment_tree {
	tree_node tree[maxn<<2];

	tree_node merge(tree_node f,tree_node g,int mid) {
		tree_node res;int mid1=mid,mid2=mid+2*n-1;
		res.a1=(f.a1)|(f.a2&&bo[mid1]&&g.a1&&bo[mid2]&&f.a4);
        //f.a2&&bo[mid1]&&g.a1&&bo[mid2]&&f.a4  1号路径
        //f.a5&&bo[mid2]&&g.a1&&bo[mid1]&&f.a6  2号路径
        //如果2号路径存在那么1号路径必然存在,所以只需要判1号路径即可
		res.a2=(f.a2&&bo[mid1]&&g.a2)|(f.a5&&bo[mid2]&&g.a6);
		res.a3=(g.a3)|(g.a2&&bo[mid1]&&f.a3&&bo[mid2]&&g.a4);
		res.a4=(f.a4&&bo[mid2]&&g.a4)|(f.a6&&bo[mid1]&&g.a5);
		res.a5=(f.a2&&bo[mid1]&&g.a5)|(f.a5&&bo[mid2]&&g.a4);
		res.a6=(f.a4&&bo[mid2]&&g.a6)|(f.a6&&bo[mid1]&&g.a2);
		return res;
	}
	
	void build(int p,int l,int r) {
		if(l==r) {
			tree[p].a2=tree[p].a4=1;
			return;
		}
		int mid=(l+r)>>1;
		build(p<<1,l,mid);
		build(p<<1|1,mid+1,r);
	}
	
	void change(int p,int l,int r,int L,int R) {
		if(l==r) {
			if(L==R) {
				tree[p].a1^=1;
				tree[p].a3^=1;
				tree[p].a5^=1;
				tree[p].a6^=1;//如果是单点修改那么这四种关系应该改变状态
			}
			return;
		}
		int mid=(l+r)>>1;
		if(L<=mid)change(p<<1,l,mid,L,R);
		else change(p<<1|1,mid+1,r,L,R);
		tree[p]=merge(tree[p<<1],tree[p<<1|1],mid);		
	}

	tree_node query(int p,int l,int r,int L,int R) {
		if(L<=l&&r<=R)return tree[p];
		int mid=(l+r)>>1;tree_node res;
		if(R<=mid)res=query(p<<1,l,mid,L,R);
		else if(L>mid)res=query(p<<1|1,mid+1,r,L,R);
		else res=merge(query(p<<1,l,mid,L,R),query(p<<1|1,mid+1,r,L,R),mid);
		return res;
	}
}T;

int main() {
	n=read();T.build(1,1,n);
	while(~scanf("%s",s+1)) {
		if(s[1]=='E')break;
		int x1=read(),y1=read(),x2=read(),y2=read();
		if(y1>y2)swap(y1,y2),swap(x1,x2);
		if(s[1]=='O'||s[1]=='C') {
			if(x1==x2) {
				int tmp=y1;
				if(x1==2)tmp+=2*n-1;
				bo[tmp]^=1;T.change(1,1,n,y1,y2);
			}
			else {
				bo[y1+n-1]^=1;
				T.change(1,1,n,y1,y2);
			}
		}
		else {
			bool ans=0;
			tree_node j=T.query(1,1,n,1,y1);
			tree_node k=T.query(1,1,n,y1,y2);
			tree_node l=T.query(1,1,n,y2,n);
			if(x1==x2) {
				if(x1==1) {
					ans|=k.a2;
					ans|=j.a3&&k.a6;
					ans|=k.a5&&l.a1;
					ans|=j.a3&&k.a4&&l.a1;
				}
				else {
					ans|=k.a4;
					ans|=j.a3&&k.a5;
					ans|=k.a6&&l.a1;
					ans|=j.a3&&k.a2&&l.a1;
				}
			}
			else {
				if(x1==1) {
					ans|=k.a5;
					ans|=j.a3&&k.a4;
					ans|=k.a2&&l.a1;
					ans|=j.a3&&k.a6&&l.a1;
				}
				else {
					ans|=k.a6;
					ans|=j.a3&&k.a2;
					ans|=k.a4&&l.a1;
					ans|=j.a3&&k.a5&&l.a1;
				}
			}//对于询问的两个点的位置一共有四种不同的关系,分别分情况讨论
			if(ans)puts("Y");
			else puts("N");
		}
	}
	return 0;
}
posted @ 2018-11-14 09:35  AKMer  阅读(154)  评论(0编辑  收藏  举报