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