BZOJ1018堵塞的交通traffic 线段树维护连通性

在地图上建线段树

[ l , r ] 区间上的线段树节点维护区域间四个顶点的连通性

随手画图差不多就是这四个顶点六条边的连通性


在查询的时候要判断一下左上和左下的点会不会经过左边区域而变得联通起来,右边也是一样

细节很多,挺难写的

#include <cassert>
#include <iostream>
#include <cstdio>
#define N 1000500

using namespace std;

struct Tree{int x1,x2,y1,y2,z1,z2;}tr[4*N],identity;
int a[N][3],b[N],c1,c2,r1,r2,n;

Tree merge(Tree p1,Tree p2,int w) {
	Tree tmp = identity;
	tmp.x1 = p1.x1 | (p1.y1 & p1.y2 & p2.x1 & a[w][1] & a[w][2]);
	tmp.x2 = p2.x2 | (p2.y1 & p2.y2 & p1.x2 & a[w][1] & a[w][2]); 
	tmp.y1 = (p1.y1 & p2.y1 & a[w][1]) | (p1.z2 & p2.z1 & a[w][2]);
	tmp.y2 = (p1.y2 & p2.y2 & a[w][2]) | (p1.z1 & p2.z2 & a[w][1]);
	tmp.z1 = (p1.y2 & p2.z1 & a[w][2]) | (p1.z1 & p2.y1 & a[w][1]);
	tmp.z2 = (p1.y1 & p2.z2 & a[w][1]) | (p1.z2 & p2.y2 & a[w][2]);
	return tmp;
}

void build(int l,int r,int t) {
	if (l == r) { tr[t].y1 = tr[t].y2 = 1; return ; }
	int mid = (l + r) / 2;
	build(l,mid,2*t); build(mid+1,r,2*t+1);
	//tr[t] = merge(tr[2*t],tr[2*t+1],mid);
}

void update(int l,int r,int t) {
	if (l == r) {
		tr[t].x1 = tr[t].x2 = b[c1];
		tr[t].z1 = tr[t].z2 = b[c1];
		tr[t].y1 = tr[t].y2 = 1;
		return ;
	}
	int mid = (l + r) / 2;
	if (c1 <= mid) update(l,mid,2*t);
	else update(mid+1,r,2*t+1);
	tr[t] = merge(tr[2*t],tr[2*t+1],mid);
}

int ll,rr;
Tree query(int l,int r,int t) {
	if (l >= ll && r <= rr) return tr[t];
	int mid = (l + r) / 2;
	if (ll > mid) return query(mid+1,r,2*t+1);
	if (rr <= mid) return query(l,mid,2*t);   
	return merge(query(l,mid,2*t),query(mid+1,r,2*t+1),mid);
}

int main()
{
	scanf("%d",&n);
	build(1,n,1);
	while (1) {
		char cmd[10];
		scanf("%s",cmd+1);  if (cmd[1] == 'E') break;
		scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
		if (cmd[1] == 'O' || cmd[1] == 'C') {
			if (c1 > c2) swap(r1,r2) , swap(c1,c2);
			int p = cmd[1] == 'O' ? 1 : 0;
			assert(r1 == r1 || c1 == c2);
			if (r1 == r2) 
				a[c1][r1] = p , update(1,n,1);
			else
				b[c1] = p , update(1,n,1);
		}
		
		if (cmd[1] == 'A') {
			if (c1 > c2) swap(r1,r2) , swap(c1,c2);
			ll = 1 ; rr = c1;
			Tree p1 = query(1,n,1);
			ll = c2 ; rr = n;
			Tree p2 = query(1,n,1);
			ll = c1 ; rr = c2;
			Tree p3 = query(1,n,1);
			int ans = 0;
			if (p1.x2) p3.x1 = 1;
			if (p2.x1) p3.x2 = 1;
			//p3.x1 |= p1.x2; p3.x2 |= p2.x1; 
			if (r1 == r2) {
				if (r1 == 1) ans = p3.y1 | (p3.x1 & p3.z1) | (p3.x2 & p3.z2) | (p3.x1 & p3.x2 & p3.y2);
				if (r1 == 2) ans = p3.y2 | (p3.x1 & p3.z2) | (p3.x2 & p3.z1) | (p3.x1 & p3.x2 & p3.y1);
			} else {
				if (r1 == 1) ans = p3.z2 | (p3.x1 & p3.y2) | (p3.x2 & p3.y1) | (p3.x1 & p3.x2 & p3.z1);
				if (r1 == 2) ans = p3.z1 | (p3.x1 & p3.y1) | (p3.x2 & p3.y2) | (p3.x1 & p3.x2 & p3.z2);
			}
			if (ans) puts("Y"); else puts("N");
		}
	}
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值