bzoj 1018: [SHOI2008]堵塞的交通traffic (线段树维护连通性)

1018: [SHOI2008]堵塞的交通traffic

Time Limit: 3 Sec   Memory Limit: 162 MB
Submit: 3192   Solved: 1062
[ Submit][ Status][ Discuss]

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

HINT

Source

[ Submit][ Status][ Discuss]

题解:线段树维护连通性

对于相邻两个点维护6个信息。

需要注意的是查询的时候,该区间的r1,r2不连通,不一定r1,r2无法连通,所以需要考虑通过两边的区间使r1,r2连通的情况。

还有对于单点的修改,所有的值都要重新计算。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 100003
using namespace std;
int n;
struct data {
	int l1,l2,h1,h2,r1,r2;//l1,l2,r1,r2是真实存在的,h1,h2每次更改都需要重新推 
	data() {
		l1=l2=h1=h2=r1=r2=0;
	}
}tr[N*4],a[N];
//l1表示左上角到右上角
//l2表示左下角到右下角 
//r1表示左上角到左下角 
//r2表示右上角到右下角 
//h1表示左上角到右下角 
//h2表示左下角到右上角 
data update(data a,data b)
{
	data t;
	t.l1=max(t.l1,a.l1&b.l1); t.l1=max(t.l1,a.h1&b.h2); 
	t.l2=max(t.l2,a.l2&b.l2); t.l2=max(t.l2,a.h2&b.h1);
	t.r1=a.r1; t.r1=max(t.r1,t.l1&t.l2&b.r2); t.r1=max(t.r1,a.l1&b.r1&a.l2);
	t.r2=b.r2; t.r2=max(t.r2,t.l1&t.l2&a.r1); t.r2=max(t.r2,b.l1&b.l2&a.r2);
	t.h1=max(t.h1,a.l1&b.h1); t.h1=max(t.h1,a.h1&b.l2);
	t.h2=max(t.h2,a.h2&b.l1); t.h2=max(t.h2,a.l2&b.h2);
	return t;
}
void pointchange(int now,int l,int r,int opt,int x,int val)
//opt=1 l1;opt=2 l2; opt=3 r1;opt=4 r2;
{
	if (x==0) return;
	if (l==r) {
		tr[now].l1=a[l].l1;
		tr[now].l2=a[l].l2;
		tr[now].r1=a[l].r1;
		tr[now].r2=a[l].r2;
		tr[now].l1=max(tr[now].l1,tr[now].r1&tr[now].l2&tr[now].r2);
		tr[now].l2=max(tr[now].l2,tr[now].r1&tr[now].l1&tr[now].r2);
		tr[now].r1=max(tr[now].r1,tr[now].l1&tr[now].r2&tr[now].l2);
		tr[now].r2=max(tr[now].r2,tr[now].l1&tr[now].r1&tr[now].l2);
		tr[now].h1=max(tr[now].r1&tr[now].l2,tr[now].l1&tr[now].r2);
		tr[now].h2=max(tr[now].r1&tr[now].l1,tr[now].l2&tr[now].r2);
		return;
	}
	int mid=(l+r)/2;
	if (x<=mid) pointchange(now<<1,l,mid,opt,x,val);
	else pointchange(now<<1|1,mid+1,r,opt,x,val);
	tr[now]=update(tr[now<<1],tr[now<<1|1]); 
}
data query(int now,int l,int r,int ll,int rr)
{
	data t;
	if (rr<ll||!ll) return t;
	if (ll<=l&&r<=rr) return tr[now];
	int mid=(l+r)/2;  bool pd=false;
	if (ll<=mid) t=query(now<<1,l,mid,ll,rr),pd=true;
	if (rr>mid)  {
		data a=query(now<<1|1,mid+1,r,ll,rr);
		if (pd) t=update(t,a);
		else t=a;
	}
	return t;
}
int main()
{
	freopen("a.in","r",stdin);
	freopen("my.out","w",stdout);
	scanf("%d",&n);
	while (true) {
		char s[10]; scanf("%s",s);
		int x,y,x0,y0; scanf("%d%d%d%d",&x0,&y0,&x,&y);
		if (y0>y) swap(x0,x),swap(y0,y);
		if (s[0]=='E') break;
		if(s[0]=='O'||s[0]=='C') {
			int opt=0; int t=0; data t1;
			if (s[0]=='O') t=1; 
			if (x0==x&&x==1) opt=1,a[y0].l1=t,pointchange(1,1,n,1,y0,t);
			if (x0==x&&x==2) opt=2,a[y0].l2=t,pointchange(1,1,n,2,y0,t);
			if (y0==y){
			  a[y].r1=t,pointchange(1,1,n,3,y,t);
			  a[y-1].r2=t,pointchange(1,1,n,4,y-1,t);
		    }
		}
		else {
			int opt; data t,t1,t2; int pd=false;
			if (x==x0&&y==y0) {
				printf("Y\n");
				continue;
			}
			if (x0==x&&x==1) {
			  t1=query(1,1,n,1,y0-1);  t2=query(1,1,n,y,n);
			  t=query(1,1,n,y0,y-1),pd=t.l1;
			  t.r1=max(t.r1,t1.r2); t.r2=max(t.r2,t2.r1);
			  pd=max(pd,t.r1&t.l2&t.r2);
		    }
			if (x0==x&&x==2){
			  t=query(1,1,n,y0,y-1),pd=t.l2;
			  t1=query(1,1,n,1,y0-1);  t2=query(1,1,n,y,n);
			  t.r1=max(t.r1,t1.r2); t.r2=max(t.r2,t2.r1);
			  pd=max(pd,t.r1&t.l1&t.r2);
		    }
			if (x0==1&&x==2&&y!=y0) {
			  t=query(1,1,n,y0,y-1),pd=t.h1;
			  t1=query(1,1,n,1,y0-1); t2=query(1,1,n,y,n);
			  t.r1=max(t.r1,t1.r2); t.r2=max(t.r2,t2.r1);
			  pd=max(pd,t.r1&t.l2); pd=max(pd,t.r2&t.l1);
			  pd=max(pd,t.r1&t.h2&t.r2);
		    }
			if (x0==2&&x==1&&y!=y0) {
			  t=query(1,1,n,y0,y-1),pd=t.h2;
			  t1=query(1,1,n,1,y0-1);  t2=query(1,1,n,y,n);
			  t.r1=max(t.r1,t1.r2); t.r2=max(t.r2,t2.r1);
			  pd=max(pd,t.r1&t.l1); pd=max(pd,t.r2&t.l2);
			  pd=max(pd,t.r1&t.h1&t.r2);
		    }
			if (x0!=x&&y==y0) {
			 t1=query(1,1,n,1,y0-1);  t2=query(1,1,n,y,n); 
			 pd=t1.r2|t2.r1;
		    }
		    if (pd) printf("Y\n");
		    else printf("N\n");
		}
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值