zoj 1391 || poj 1436 Horizontally Visible Segments

211 篇文章 0 订阅

给你N条线段(垂直于x轴)的两个y坐标还有x坐标,问相互看到的三元组有多少个。

相互看到指能用一条水平线连起来而且不经过其他线段。

刚开始就想到暴力了,可是很纠结的,如果用线段树计算出相互能看到的对数,然后再暴力,这个时间复杂度不会算,囧。。。

虽然才8000线段,应该不是太大。。。就试了试。

有点纠结就是,如果两个连线之间正好有一条线段的某个端点,这个也是不能计算的,所以这个端点就有意义了,所以就用上面那个题的做法,全部扩大二倍再用线段树。

开始更新到底了,真傻了,后来暴力居然在ZOJ8秒过了,桑心啊。。人家都100+ms过的。。

后来发现,不用更新到底,更新到被某条线段覆盖了即可,改了改。

开始我计算重复了,很慢,后来用后面的连前面的(开始我弄的是双向的囧。。),再枚举同一个父亲的两个线段是否能相互看到,这个计算量又小了很多。

学习了下vector的unique用法,我开始是用一个bool数组标记了,如果加边一次,下一次就不加了,不好的是每次都要memset。。

unique是把不同的元素覆盖到数组前面,但是vector的size不变,如果要改变的话(因为我下面用的二分。。如果size不变的话会出错),用v.resize..

具体的unique用法见 http://cplusplus.com/reference/algorithm/unique/

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define FOR(i,s,t) for(int i=(s); i<(t); i++)
#define BUG puts("here!!!")
#define STOP system("pause")
#define file_r(x) freopen(x, "r", stdin)
#define file_w(x) freopen(x, "w", stdout)

using namespace std;

const int MAX = 8010*2;
struct Tnode{				// 一维线段树 
    int l,r,id;
    int len() { return r - l;}
    int mid() { return MID(l,r);}
    bool in(int ll,int rr) { return l >= ll && r <= rr; }
    void lr(int ll,int rr){ l = ll; r = rr;}
};
Tnode node[MAX<<2];
vector< vector<int> > v(MAX/2);
vector< int >::iterator it;
void Build(int t,int l,int r)
{
	node[t].lr(l,r);
	node[t].id = -1;			//未被赋值为-1,混合色为-2 
	if( node[t].len() == 1 )
		return ;
	int mid = MID(l,r);
	Build(L(t),l,mid);
	Build(R(t),mid,r);
}
void Updata_id(int t)
{
	if( node[L(t)].id == node[R(t)].id && node[L(t)].id != -2 )
		node[t].id = node[L(t)].id;
	else
		node[t].id = -2;
}

void Push_down(int t)
{
	if( node[t].len() == 1 )
		return ;
	if( node[t].id >= 0 )
		node[L(t)].id = node[R(t)].id = node[t].id;
}
void Updata(int t,int l,int r,int id)
{
	Push_down(t);
	if( node[t].in(l,r) && node[t].id != -2 )
	{
		if( node[t].id != -1 )
			v[node[t].id].push_back(id);
		node[t].id = id;
		return ;
	}
	if( node[t].len() == 1 ) return ;
	int mid = node[t].mid();
	if( l < mid ) Updata(L(t),l,r,id);
	if( r > mid ) Updata(R(t),l,r,id);
	Updata_id(t);
}

struct NODE{
	int x, y, id, xx;	// x < y 
	void get()
	{
		scanf("%d%d%d", &x, &y, &xx);
	}
};
NODE a[MAX/2];
bool cmp(NODE a,NODE b)
{
	return a.xx < b.xx;
}
int solve(int n)
{
	int sum = 0;
	Build(1, 0, MAX);

	FOR(i, 0, n)
	{
		v[i].clear();
		Updata(1, a[i].x*2, a[i].y*2+1, a[i].id);
	}
	
	FOR(i, 0, n)
	{
		sort(v[i].begin(), v[i].end());
		it = unique(v[i].begin(), v[i].end());
		v[i].resize( it - v[i].begin());
	}
	
	FOR(i, 0, n)
	{
		int len = v[i].size();
		FOR(k, 0, len)
		{
			FOR(j, k+1, len) // 经测试,根据POJ的数据,最内层这个计算量不到50w 
			{				
				int a = v[i][k];
				int b = v[i][j];
				if( binary_search(v[a].begin(), v[a].end(), b) )
					sum++;
			}
		}
	}
	return sum;		
}
		
int main()
{
	int ncases, n;
	
	scanf("%d", &ncases);
	
	while( ncases-- )
	{
		scanf("%d", &n);
		FOR(i, 0, n)
			a[i].get();

		sort(a, a+n, cmp);
		
		FOR(i, 0, n)
			a[i].id = i;
		int ans = solve(n);
		
		printf("%d\n", ans);
	}
			
return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值