ZOJ 1391 Horizontally Visible Segments(线段树)

17 篇文章 0 订阅

首先对线段按照x坐标排序,对于每一条线段的y坐标都乘以2,因为如果有两条同一x坐标的线段分别y坐标为1-2,3-4 2和3之间其实是可以通过的.如果不乘二就会被忽略掉了.

然后按顺序插入每一条线段,每条线段染一种颜色,对于后面插入的线段i首先查询下 [yi1,yi2]区间里的能看见的颜色,这些颜色的线段就可以看见线段i,然后把这些颜色的线段的vector里插入i.

因为里面有很多重复的数据,所以用一下unique.

最后枚举一下.

#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <vector>
using namespace std;
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
const int maxn=17000;
int segs[maxn*3], n, m;
vector<int>vs[maxn/2];
struct segment{
	int y1,y2,x;
	bool operator<(const segment & rhs)const{
		return x < rhs.x;
	}
}ss[maxn/2];

void build(int l,int r,int rt){
	segs[rt] = 0;
	if (l == r){
		return;
	}
	int m = (l + r) >> 1;
	build(lson), build(rson);
}
void query(int L, int R, int l, int r, int rt, int id){
	if (segs[rt]){
		vs[segs[rt]].push_back(id);
		return;
	}
	if(l == r) return;
	if(segs[rt]){
		segs[rt << 1] = segs[rt << 1 | 1] = segs[rt];
		segs[rt]=0;
	}
	int m = (l + r) >> 1;
	if(L <= m)query(L, R, lson, id);
	if(R > m)query(L, R, rson, id);
}
void update(int L, int R, int l, int r, int rt, int id){
	if (L <= l && r <= R){
		segs[rt] = id;
		return ;
	}
	int m = (l + r) >> 1;
	if(segs[rt]){
		segs[rt << 1] = segs[rt << 1 | 1] = segs[rt];
		segs[rt]=0;
	}
	if(L <= m)update(L, R, lson, id);
	if(R > m)update(L, R, rson, id);
}
int main(){
	int t;
	scanf("%d",&t);
	while (t--){
		scanf("%d",&n);
		int maxy=0;

		for (int i=1;i<=n;++i){
			scanf("%d%d%d", &ss[i].y1, &ss[i].y2, &ss[i].x);
			ss[i].y1 = (ss[i].y1 << 1) + 1;
			ss[i].y2 = (ss[i].y2 << 1) + 1;
			maxy = max(maxy, max(ss[i].y2, ss[i].y1));
			vs[i].clear();
		}
		build(1, maxy, 1);
		sort(ss + 1, ss + n + 1);
		for (int i = 1; i <= n; ++i){
			query(ss[i].y1, ss[i].y2, 1, maxy, 1, i);
			update(ss[i].y1, ss[i].y2, 1, maxy, 1, i);
		}
		int ans = 0;
		for (int i = 1 ; i <= n; ++i){
			vs[i].erase(unique(vs[i].begin(),vs[i].end()), vs[i].end());
		}
		for (int i = 1 ; i <= n; ++i){
			int si = vs[i].size();
			for (int j = 0; j < si; ++j){
				for (int k = j + 1; k < si; ++k){
					int sk = vs[vs[i][j]].size();
					for (int l = 0; l < sk; ++l){
						if (vs[vs[i][j]][l] == vs[i][k]){
							ans++;
							break;
						}
					}
				}
			}
		}
		printf("%d\n",ans) ;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值