[BZOJ 1018] [SHOI2008] 堵塞的交通traffic 【线段树维护联通性】

题目链接:BZOJ - 1018

题目分析

这道题就说明了刷题少,比赛就容易跪..SDOI Round1 Day2 T3 就是与这道题类似的..然而我并没有做过这道题..

这道题是线段树维护联通性的经典模型。

我们线段树的一个节点表示一个区间的联通性,有 6 个 bool 值,表示这个区间的 4 个角上的点之间的联通性。

然后用两个子区间的联通性和两个子区间之间的连边情况合并出整个区间的联通性。

修改某条边时,先在边的数组中修改,然后从这条边所在的点的线段树叶子开始向上 Update 。

询问两点之间的联通性时,假如它们的列分别是 y1, y2, 那么我们要求出 [1, y1] [y1, y2] [y2, n] 的联通性。

然后用这三个联通性组合起来手动枚举各种情况判断两个点是否联通。

因为分别处于 y1, y2 的两个点,之间可能不只是通过 [y1, y2] 之间的边联通,而是需要用到两侧的边连接起来。

代码

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

inline int gmin(int a, int b) {return a < b ? a : b;}
inline int gmax(int a, int b) {return a > b ? a : b;}

const int MaxN = 100000 + 5;

int n;

char Str[15];

bool A[MaxN][3];

struct ES
{
	bool a1, a2, b1, b2, c1, c2;
} T[MaxN * 4]; 

inline ES Plus(ES e1, ES e2, int m)
{
	ES ret;
	ret.a1 = e1.a1 || (e1.b1 && e1.b2 && A[m][1] && A[m][2] && e2.a1);
	ret.a2 = e2.a2 || (e2.b1 && e2.b2 && A[m][1] && A[m][2] && e1.a2);
	ret.b1 = (e1.b1 && A[m][1] && e2.b1) || (e1.c1 && A[m][2] && e2.c2);
	ret.b2 = (e1.b2 && A[m][2] && e2.b2) || (e1.c2 && A[m][1] && e2.c1);
	ret.c1 = (e1.b1 && A[m][1] && e2.c1) || (e1.c1 && A[m][2] && e2.b2);
	ret.c2 = (e1.b2 && A[m][2] && e2.c2) || (e1.c2 && A[m][1] && e2.b1);
	return ret;
}

void Build(int x, int s, int t)
{
	if (s == t)
	{
		T[x].a1 = T[x].a2 = T[x].c1 = T[x].c2 = false;
		T[x].b1 = T[x].b2 = true;
		return;
	}
	int m = (s + t) >> 1;
	Build(x << 1, s, m);
	Build(x << 1 | 1, m + 1, t);
	T[x] = Plus(T[x << 1], T[x << 1 | 1], m);
}

void Modify(int x, int s, int t, int Pos)
{
	if (s == t)
	{
		T[x].a1 = T[x].a2 = T[x].c1 = T[x].c2 = A[Pos][0];
		T[x].b1 = T[x].b2 = true;
		return;
	}
	int m = (s + t) >> 1;
	if (Pos <= m) Modify(x << 1, s, m, Pos);
	else Modify(x << 1 | 1, m + 1, t, Pos);
	T[x] = Plus(T[x << 1], T[x << 1 | 1], m);
}

ES Get(int x, int s, int t, int l, int r)
{
	if (l <= s && r >= t) return T[x];
	ES ret;
	int m = (s + t) >> 1;
	if (r <= m) ret = Get(x << 1, s, m, l, r);
	else if (l >= m + 1) ret = Get(x << 1 | 1, m + 1, t, l, r);
	else ret = Plus(Get(x << 1, s, m, l, r), Get(x << 1 | 1, m + 1, t, l, r), m);
	return ret;
}

int main()
{
	scanf("%d", &n);
	int x, y, xx, yy;
	bool f, Ans;
	ES El, Ex, Er;
	Build(1, 1, n);
	while (true)
	{
		scanf("%s", Str);
		if (strcmp(Str, "Exit") == 0) break;
		scanf("%d%d%d%d", &x, &y, &xx, &yy);
		if (strcmp(Str, "Ask") == 0)
		{
			if (y > yy)
			{
				swap(x, xx);
				swap(y, yy);
			}
			El = Get(1, 1, n, 1, y);
			Ex = Get(1, 1, n, y, yy);
			Er = Get(1, 1, n, yy, n);
			if (x == xx)
			{
				if (x == 1)
					Ans = Ex.b1 || 					(A[y - 1][1] && A[y - 1][2] && El.a2 && Ex.c2) || 					(A[yy][1] && A[yy][2] && Er.a1 && Ex.c1) || 					(A[y - 1][1] && A[y - 1][2] && El.a2 && A[yy][1] && A[yy][2] && Er.a1 && Ex.b2);
				else
					Ans = Ex.b2 || 					(A[y - 1][1] && A[y - 1][2] && El.a2 && Ex.c1) || 					(A[yy][1] && A[yy][2] && Er.a1 && Ex.c2) || 					(A[y - 1][1] && A[y - 1][2] && El.a2 && A[yy][1] && A[yy][2] && Er.a1 && Ex.b1);
			}
			else
			{
				if (x < xx)
					Ans = Ex.c1 || 					(A[y - 1][1] && A[y - 1][2] && El.a2 && Ex.b2) || 					(Ex.b1 && A[yy][1] && A[yy][2] && Er.a1);
				else
					Ans = Ex.c2 || 					(A[y - 1][1] && A[y - 1][2] && El.a2 && Ex.b1) || 					(Ex.b2 && A[yy][1] && A[yy][2] && Er.a1);
			}
			if (Ans) printf("Y\n");
			else printf("N\n");
		}
		else
		{
			if (strcmp(Str, "Open") == 0) f = true;
			else f = false;
			if (x == xx)
			{
				A[gmin(y, yy)][x] = f;
				Modify(1, 1, n, gmin(y, yy));
			}
			else
			{
				A[y][0] = f;
				Modify(1, 1, n, y);
			}
		}
	}
	return 0;
}

  

时间: 2024-10-27 10:35:03

[BZOJ 1018] [SHOI2008] 堵塞的交通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条道路. 小人国的交通

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

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

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

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

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

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

[BZOJ 1018][SHOI2008]堵塞的交通traffic(线段树)

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

bzoj 1018: [SHOI2008]堵塞的交通traffic

由于只有两行,对一个区间可以维护四个角上的连通性 一共6个量,满足区间可加性,用线段树维护,查询时找出3段的量,看是否满足题解上的三种情况之一. 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<queue> 7 #include<algorithm> 8

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 [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

1018: [SHOI2008]堵塞的交通traffic

1018: [SHOI2008]堵塞的交通traffic 链接 分析: 用线段树维护区间的四个端点的联通情况,然后查询的时候,把所有覆盖到的区间合并起来即可. 六种情况左上到右上(左边到右边的情况)……,左上到左下(同一侧相互到达的情况)…… 同一侧相互到达的情况,查询[l,r]是查的不完全.因为还有可能是先往左边走几步,下去,在走回来.这时候,查询一下[1,l]的情况,或起来即可. 代码: 1 #include<cstdio> 2 #include<algorithm> 3 #i