首页 > 代码库 > POJ 1436 Horizontally Visible Segments(线段树)

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;
}


POJ 1436 Horizontally Visible Segments(线段树)