bzoj 1018 堵塞的交通traffic 线段树

题意:有一个n * 2的网格图,有3种操作:给两个相邻的点加上一条边,断开相邻的两个点连着的边,询问两个点的连通性。

思路:直接看博客就行了,https://blog.csdn.net/roll_keyboard/article/details/81185535,在纸上画一画来确定4个顶点之间的更新关系。有一个需要注意的细节是有可能通过绕远路的方式可以到达,所以需要考虑前面和后面的部分对询问区间的影响。

代码:

#include <bits/stdc++.h>
#define ls (o << 1)
#define rs (o << 1 | 1)
using namespace std;
const int maxn = 100010;
struct node {
	bool l, r, u, d, x1, x2, U, D;
};
node tr[maxn * 4];
node init() {
	node ans;
	ans.l = ans.r = ans.D = ans.U = ans.x1 = ans.x2 = 0;
	ans.u = ans.d = 1;
	return ans;
}
node merge(node a1, node a2) {
	node ans;
	ans.l = (a1.l | (a1.u & a1.U & a2.l & a1.D & a1.d));
	ans.r = (a2.r | (a2.u & a1.U & a1.r & a1.D & a1.d));
	ans.u = ((a1.u & a1.U & a2.u) | (a1.x1 & a1.D & a2.x2));
	ans.d = ((a1.d & a1.D & a2.d) | (a1.x2 & a1.U & a2.x1));
	ans.x1 = ((a1.u & a1.U & a2.x1) | (a1.x1 & a1.D & a2.d));
	ans.x2 = ((a1.x2 & a1.U & a2.u) | (a1.d & a1.D & a2.x2));
	ans.U = a2.U;
	ans.D = a2.D;
	return ans;
}
void build(int o, int l, int r) {
	if(l == r) {
		tr[o] = init();
		return;
	}
	int mid = (l + r) >> 1;
	build(ls, l, mid);
	build(rs, mid + 1, r);
	tr[o] = merge(tr[ls], tr[rs]);
}
void update(int o, int l, int r, int p, int type) {
	if(l == r) {
		if(type >> 2) {
			tr[o].l = tr[o].r = tr[o].x1 = tr[o].x2 = (type & 1);
			return;
		} else if (type >> 1) {
			tr[o].U = (type & 1);
		} else {
			tr[o].D = (type & 1);
		}
		return;
	}
	int mid = (l + r) >> 1;
	if(p <= mid) update(ls, l, mid, p, type);
	else update(rs, mid + 1, r, p, type);
	tr[o] = merge(tr[ls], tr[rs]);
}
node query(int o, int l, int r, int ql, int qr) {
	if(l >= ql && r <= qr) {
		return tr[o];
	}
	int mid = (l + r) >> 1;
	node ans = init();
	ans.U = ans.D = 1;
	if(ql <= mid) ans = merge(ans, query(ls, l, mid, ql, qr));
	if(qr > mid) ans = merge(ans, query(rs, mid + 1, r, ql, qr));
	return ans;
}
void out(bool flag) {
	if(flag) printf("Y\n");
	else printf("N\n");
}
char s[10];
int main() {
	int n;
	scanf("%d", &n);
	int x1, y1, x2, y2;
	build(1, 1, n);
	while(1) {
		scanf("%s", s + 1);
		if(s[1] == ‘E‘) break;
		scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
		if(y1 > y2) {
			swap(x1, x2);
			swap(y1, y2);
		}
		if(s[1] == ‘A‘) {
			node ans1, ans2, ans3;
			if(y1 > 1) ans1 = query(1, 1, n, 1, y1 - 1);
			ans2 = query(1, 1, n, y1, y2);
			if(y2 < n) ans3 = query(1, 1, n, y2 + 1, n);
			if(y1 > 1 && (ans1.r && ans1.U && ans1.D)) {
				ans2.l |= 1;
				ans2.x1 |= (ans2.l & ans2.d);
				ans2.x2 |= (ans2.l & ans2.u);
				ans2.d |= (ans2.x1 & ans2.l);
				ans2.u |= (ans2.l & ans2.x2);
			}
			if(y2 < n && (ans2.U && ans3.l && ans2.D)) {
				ans2.r |= 1;
				ans2.x1 |= (ans2.u & ans2.r);
				ans2.x2 |= (ans2.d & ans2.r);
				ans2.d |= (ans2.x2 & ans2.r);
				ans2.u |= (ans2.x1 & ans2.r);
			}
			if(x1 == 1 && x2 == 1) {
				out(ans2.u);
			} else if(x1 == 1 && x2 == 2) {
				out(ans2.x1);
			} else if(x1 == 2 && x2 == 1) {
				out(ans2.x2);
			} else {
				out(ans2.d);
			}
		} else {
			int type = 0;
			if(y1 == y2) {
				type |= (1 << 2);
				if(s[1] == ‘O‘) type |= 1;
			} else {
				if(x1 == 1) type |= (1 << 1);
				if(s[1] == ‘O‘) type |= 1;
			}
			update(1, 1, n, y1, type);
		}
	}
}

  

原文地址:https://www.cnblogs.com/pkgunboat/p/11445883.html

时间: 2024-10-10 05:47:17

bzoj 1018 堵塞的交通traffic 线段树的相关文章

BZOJ 1018: [SHOI2008]堵塞的交通traffic [线段树 区间信息]

1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 3064  Solved: 1027[Submit][Status][Discuss] Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个城市和3C-2条道路. 小人国的交通

【BZOJ1018】[SHOI2008]堵塞的交通traffic 线段树

[BZOJ1018][SHOI2008]堵塞的交通traffic Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个城市和3C-2条道路. 小人国的交通状况非常槽糕.有的时候由于交通堵塞,两座城市之间的道路会变得不连通,直到拥堵解决,道路才会恢复畅通.初来咋到的你决心毛遂自荐到交通部某份差事,部长听说你来自一个科技高度发达的

BZOJ 1018 SHOI2008 堵塞的交通traffic 线段树

题目大意:给定一张2*n的网格图,多次改变某条边是否可用,多次查询某两个点是否联通 多(yi)年前的我看到这题的第一反应是:这题尼玛能做? 两个点之间的路径可能是这样的: 也可能是这样的: 甚至可能是这样的: 这题能写? 这题其实好写爆了 我们首先忽略第三种情况,假设所有对答案有贡献的边都在两个点的中间 那么我们以每一列为一个叶节点建立线段树 线段树的每个节点开一个二维数组a[2][2] 其中 a[x][y]记录当前区间的左端点的第x行和右端点的第y行是否联通 那么合并如下: 例如,a[0][0

bzoj1018 [SHOI2008]堵塞的交通traffic——线段树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1018 线段树竟然还可以这样用! 维护的是一个矩形内部的连通情况,四个顶点之间有6中连通方式: 因为连通情况具有可合并性,所以可以用线段树来维护! 这篇博客写得很好:https://www.cnblogs.com/DUXT/p/6029815.html 茅塞顿开之后看到这篇博客,觉得写得很好呢:https://www.cnblogs.com/MashiroSky/p/5973686.html

bzoj 1018 堵塞的交通traffic

题外话 做了这个线段树的题我整个人都不好了,头一次做这种用线段树维护连通性的题,简直烦的要死= = Description 给你一个2*n的格子,开始全不联通,相邻两点可以连边,有3种操作 1:将(x1,y1),(x2,y2)变为连通 2:将(x1,y1),(x2,y2)变为不连通 3:询问(x1,y1),(x2,y2)是否联通 Soluion 用线段树维护6个信息,正常的4条边以及两条对角线是否联通,修改时用线段树维护 最蛋疼的是查询,比如[l,r]区间,不一定连通性只是在这个区间内的 比如虽

bzoj1018: [SHOI2008]堵塞的交通traffic 线段树

线段树维护每一块左上到左下.右上到右下.左上到右上.左下到右下.左上到右下.左下到右上的联通情况. #include<bits/stdc++.h> #define N 100005 #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define K l,r,k #define L l,M,P #define R M+1,r,S #define Z int l=1,int r=n,int k=1 u

【BZOJ1018】堵塞的交通(线段树)

[BZOJ1018]堵塞的交通(线段树) 题面 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可 以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个 城市和3C-2条道路. 小人国的交通状况非常槽糕.有的时候由于交通堵塞,两座城市之间的道路会变得不连通, 直到拥堵解决,道路才会恢复畅通.初来咋到的你决心毛遂自荐到交通部某份差事,部长听说你来自一个科技高度 发达的世界,喜出

数据结构(线段树):BZOJ 1018: [SHOI2008]堵塞的交通traffic

1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 2638  Solved: 864 Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有2C个城市和3C-2条道路. 小人国的交通状况非常槽糕.有的时候由于交通堵塞,两座城市之间的道

【BZOJ】【1018】【SHOI2008】堵塞的交通traffic

线段树 这题的线段树+分类讨论蛮神奇的……我以前学的线段树简直就是渣渣QAQ 看了下ydc题解里的思想>_>用线段树维护连通性!那么就自己写吧……每个节点表示一段区间的连通性(我的叶子节点表示的是一个方块型的四个点之间的连通性,所以我直接n--了)对线段树上每个节点维护6个信息,即四个端点中任意一对点之间的连通性. 维护连通性的时候要进行信息的整合,也就是说间接连通的要全部找到并标记上连通,举个例子:如果左边连通且下边两端点连通,则左上到右下连通.这是一个简单的讨论我就不细说了,自己想一下真的