POJ 1436 Horizontally Visible Segments(线段树)

POJ 1436 Horizontally Visible Segments

题目链接

线段树处理染色问题,把线段排序,从左往右扫描处理出每个线段能看到的右边的线段,然后利用bitset维护枚举两个线段,找出另一个两个都有的线段

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bitset>
#include <vector>
using namespace std;

const int N = 8005;
bitset<N> g[N];
int t, n;

struct Seg {
	int x, y1, y2;
	void read() {
		scanf("%d%d%d", &y1, &y2, &x);
	}
} s[N];

bool cmp(Seg a, Seg b) {
	return a.x < b.x;
}

#define lson(x) ((x<<1)+1)
#define rson(x) ((x<<1)+2)

struct Node {
	int l, r, val, setv;
} node[N * 4 * 2];

void pushup(int x) {
	if (node[lson(x)].val == node[rson(x)].val) node[x].val = node[lson(x)].val;
	else node[x].val = -1;
}

void pushdown(int x) {
	if (node[x].setv != -1) {
		node[lson(x)].val = node[rson(x)].val = node[x].setv;
		node[lson(x)].setv = node[rson(x)].setv = node[x].setv;
		node[x].setv = -1;
	}
}

void build(int l, int r, int x = 0) {
	node[x].l = l; node[x].r = r; node[x].val = -1; node[x].setv = -1;
	if (l == r)
		return;
	int mid = (l + r) / 2;
	build(l, mid, lson(x));
	build(mid + 1, r, rson(x));
}

vector<int> g2[N];

void add(int l, int r, int v, int x = 0) {
	if (node[x].val != -1 && node[x].l >= l && node[x].r <= r) {
		if (g[node[x].val][v] == false)
			g2[node[x].val].push_back(v);
		g[node[x].val][v] = true;
		node[x].setv = v;
		node[x].val = v;
		return;
	}
	if (node[x].l == node[x].r) {
		node[x].val = v;
		return;
	}
	pushdown(x);
	int mid = (node[x].l + node[x].r) / 2;
	if (l <= mid) add(l, r, v, lson(x));
	if (r > mid) add(l, r, v, rson(x));
	pushup(x);
}

int main() {
	scanf("%d", &t);
	while (t--) {
		scanf("%d", &n);
		for (int i = 0; i < n; i++) {
			g[i].reset();
			g2[i].clear();
			s[i].read();
		}
		sort(s, s + n, cmp);
		build(0, N * 2 - 1);
		for (int i = 0; i < n; i++)
			add(s[i].y1 * 2, s[i].y2 * 2, i);
		int ans = 0;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < g2[i].size(); j++) {
				if (g[i][g2[i][j]])
					ans += (g[i]&g[g2[i][j]]).count();
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}
时间: 2024-10-14 16:22:35

POJ 1436 Horizontally Visible Segments(线段树)的相关文章

POJ 1436 Horizontally Visible Segments (线段树&amp;#183;区间染色)

题意   在坐标系中有n条平行于y轴的线段  当一条线段与还有一条线段之间能够连一条平行与x轴的线不与其他线段相交  就视为它们是可见的  问有多少组三条线段两两相互可见 先把全部线段存下来  并按x坐标排序  线段树记录相应区间从右往左当前可见的线段编号(1...n)  超过一条就为0  然后从左往右对每条线段  先查询左边哪些线段和它是可见的  把可见关系存到数组中  然后把这条线段相应区间的最右端可见编号更新为这条线段的编号  最后暴力统计有多少组即可了 #include <cstdio>

(中等) POJ 1436 Horizontally Visible Segments , 线段树+区间更新。

Description There is a number of disjoint vertical line segments in the plane. We say that two segments are horizontally visible if they can be connected by a horizontal line segment that does not have any common points with other vertical segments.

POJ 1436 Horizontally Visible Segments(线段树建图+枚举)

题目连接:http://poj.org/problem?id=1436 题意:给一些线段,每个线段有三个值y1, y2, x代表起点为(x, y1),终点为(x, y2)的线段.当从一个线段可以作水平线到另一个线段并且不穿过其他线段时,就称这两个线段时水平可见的.当三个线段可以两两水平可见,就称为形成一个线段三角.问:在这些线段中有多少个这样的线段三角? 分析:可以把每条线段看做是一个点,如果它和其他线段是水平可见的,就将这两个点相连,由于是无向图,就是你能看到我,我也能看到你,所以需要连接两次

POJ - 1436 Horizontally Visible Segments

Description There is a number of disjoint vertical line segments in the plane. We say that two segments are horizontally visible if they can be connected by a horizontal line segment that does not have any common points with other vertical segments.

poj 1436 Horizontally Visible Segments(线段树、区间覆盖)

Horizontally Visible Segments Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4645   Accepted: 1706 Description There is a number of disjoint vertical line segments in the plane. We say that two segments are horizontally visible if they

POJ 1436——Horizontally Visible Segments(线段树,区间染色+暴力)

Horizontally Visible Segments Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4130   Accepted: 1511 Description There is a number of disjoint vertical line segments in the plane. We say that two segments are horizontally visible if they

POJ 1436 Horizontally Visible Segments(线段树区间修改)

题目链接:点击打开链接 题意:n条竖直线段,如果两条线段之间可见(即可以用一条水平线段连接而不触碰其他线段),则称它们可见.   如果三条线段任意两条都可见, 则称它们为a triangle of segments, 求a triangle of segments的个数 思路: 一开始真没想到n^3的复杂度可以过...  如果这样的话, 问题的关键就是怎样判断任意两个线段是否可见. 那么如果对y坐标建立区间, 这就成了线段树的区间覆盖问题. 另外, 由于是用点代替线段, 所以对于"可见"

Poj1436Horizontally Visible Segments线段树

#include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <set> #include <qu

POJ1436Horizontally Visible Segments线段树+lazy

判断3条线段是否联通,如果任意2条线段联通,则3条线段联通:开一个hash[i][j]保存第i条线段和第j条线段的关系,每次插入新的线段前都需要先判断此直线是否与前面的其他线段联通,再将这条线段插入:PS:要注意的一点是需要先对所有的线段关于x坐标进行排序,然后再按照熟顺序插入线段: #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <