【bzoj1018】 堵塞的交通 线段树维护连通性

真是道神题,想写了一个月终于今天晚上把它解决了。想一下也真心不容易。我们用线段树维护这样几个量。

(懒得画了,原谅我盗图。。。)

我们用线段树维护这六个量,然后用一个数组a[x][0][0]表示第1行x位置与x+1位置的连通性,a[x][1][0]表示第二行x位置和x+1位置的连通性,a[x][0][1]表示第一行x位置与第二行x位置的连通性。线段树的合并和查询写的比较巧妙,具体细节可以参见代码。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 100010

using namespace std;

struct yts
{
	bool s[2],x[2],v[2];
};

struct yts1
{
	yts a;
	int l,r;
}t[4*maxn];

bool a[maxn][2][2];
char s[10];
int T,n,r1,r2,c1,c2;
int dx[3]={-1,0,1};
int dy[3]={0,1,0};

void print(yts a)
{
	printf("x:%d  %d\ns:%d  %d\nv:%d  %d\n",a.x[0],a.x[1],a.s[0],a.s[1],a.v[0],a.v[1]);
}

void build(int i,int l,int r)
{
	t[i].l=l;t[i].r=r;
	if (l==r) {t[i].a.x[0]=t[i].a.x[1]=1;return;}
	int mid=(l+r)>>1;
	build(i<<1,l,mid);build(i<<1|1,mid+1,r);
}

void updata(yts &u,yts l,yts r,int mid)
{
	u.s[0]= l.s[0] || (l.x[0]&&a[mid][0][0]&&a[mid][1][0]&&r.s[0]&&l.x[1]);//左上左下 
	u.s[1]= r.s[1] || (r.x[0]&&a[mid][0][0]&&a[mid][1][0]&&l.s[1]&&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.v[0]&&a[mid][1][0]&&r.x[1]) || (l.x[0]&&a[mid][0][0]&&r.v[0]);//左上右下
	u.v[1]= (l.v[1]&&a[mid][0][0]&&r.x[0]) || (l.x[1]&&a[mid][1][0]&&r.v[1]);//左下右上 
}

void modify(int i,int x)
{
	if (t[i].l==t[i].r)
	{
		t[i].a.s[0]=t[i].a.s[1]=t[i].a.v[0]=t[i].a.v[1]=a[x][0][1];
		t[i].a.x[0]=t[i].a.x[1]=1;
		return;
	}
	int mid=(t[i].l+t[i].r)>>1;
	if (x<=mid) modify(i<<1,x);
	else modify(i<<1|1,x);
	updata(t[i].a,t[i<<1].a,t[i<<1|1].a,(t[i].l+t[i].r)>>1);
}

void change(bool f)
{
	if (r1>r2) swap(r1,r2),swap(c1,c2);
	int dir;
	for (int i=0;i<3;i++)
	  if (c1+dx[i]==c2 && r1+dy[i]==r2) dir=i;
	if (dir==0) a[c2][r2][0]=f,modify(1,c2);
	else if (dir==1) a[c2][0][1]=f,modify(1,c2);
	else a[c1][r1][0]=f,modify(1,c1);
}

yts query(int i,int l,int r)
{
	if (l<=t[i].l && t[i].r<=r) return t[i].a;
	int mid=(t[i].l+t[i].r)>>1;
	if (r<=mid) return query(i<<1,l,r);
	if (l>mid) return query(i<<1|1,l,r);
	yts a=query(i<<1,l,r),b=query(i<<1|1,l,r),ans;
	updata(ans,a,b,(t[i].l+t[i].r)>>1);
	return ans;
}

void getans()
{
	if (c1>c2) swap(c1,c2),swap(r1,r2);
	yts pa,pb,pc;
	pa=query(1,1,c1);
	pb=query(1,c1,c2);
	pc=query(1,c2,n);
	if (r1==r2)
	{
		if (r1==0)
		{
			if (pb.x[0]||(pa.s[1]&&pb.v[1])||(pb.v[0]&&pc.s[0])||(pa.s[1]&&pb.x[1]&&pc.s[0])) puts("Y");
			else puts("N");
		}
		else
		{
			if (pb.x[1]||(pa.s[1]&&pb.v[0])||(pb.v[1]&&pc.s[0])||(pa.s[1]&&pb.x[0]&&pc.s[0])) puts("Y");
			else puts("N");
		}
	}
	else
	{
		if (r1==0)
		{
			if (pb.v[0]||(pa.s[1]&&pb.x[1])||(pc.s[0]&&pb.x[0])) puts("Y");
			else puts("N");
		}
		else
		{
			if (pb.v[1]||(pa.s[1]&&pb.x[0])||(pc.s[0]&&pb.x[1])) puts("Y");
			else puts("N");
		}
	}
}

int main()
{
	scanf("%d",&n);
	build(1,1,n);
	while (1)
	{
		scanf("%s",s);
		if (s[0]=='E') break;
		scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
		r1--;r2--;
		if (s[0]=='O') change(1);
		else if (s[0]=='C') change(0);
		else getans();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值