POJ_1436
这个题目最后统计的时候直接暴力即可,一开始想的时候以为这样过不了的,没想到大家都是暴力统计的……而且我用“优化”后的局部O(nlogn)的统计方式(注释部分的代码),反倒没有局部O(n^2)的统计方式快,看来真正horizontally visible的线段对确实比较少。
至于查询的过程,我们可以先把线段按x排序,然后逐一扫描,查询每个线段的下面还有哪些线段是可以“看得到”的,查询完之后再把线段所在的区间染色即可。
此外,由于如果我们将每个纵坐标看作一个区间的话,这样两个相邻的纵坐标之间就没有空当了,所以为了避免丢解,可以把线段的坐标全部乘以2,这样奇数的坐标就表示了两个纵坐标之间的空当。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXD 8010
#define D 16000
#define INF 0x3f3f3f3f
#define MAXM 1000010
struct Seg
{
int id, x, y1, y2;
}seg[MAXD];
int N, tree[8 * MAXD], to[8 * MAXD], a[MAXD], b[MAXD], A, B, e, first[MAXD], next[MAXM], v[MAXM], hash[MAXD];
int cmpx(const void *_p, const void *_q)
{
Seg *p = (Seg *)_p, *q = (Seg *)_q;
return p->x - q->x;
}
int cmpid(const void *_p, const void *_q)
{
int *p = (int *)_p, *q = (int *)_q;
return *p - *q;
}
void pushdown(int cur)
{
int ls = cur << 1, rs = (cur << 1) | 1;
if(to[cur] != -1)
{
to[ls] = to[rs] = to[cur];
tree[ls] = tree[rs] = to[cur];
to[cur] = -1;
}
}
void update(int cur)
{
int ls = cur << 1, rs = (cur << 1) | 1;
if(tree[ls] == tree[rs])
tree[cur] = tree[ls];
else
tree[cur] = INF;
}
void build(int cur, int x, int y)
{
int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
tree[cur] = to[cur] = -1;
if(x == y)
return ;
build(ls, x, mid);
build(rs, mid + 1, y);
}
void init()
{
int i;
scanf("%d", &N);
for(i = 0; i < N; i ++)
{
scanf("%d%d%d", &seg[i].y1, &seg[i].y2, &seg[i].x);
seg[i].id = i;
}
build(1, 0, D);
qsort(seg, N, sizeof(seg[0]), cmpx);
}
void query(int cur, int x, int y, int s, int t, int id)
{
int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
if(x >= s && y <= t)
{
if(tree[cur] != INF)
{
if(tree[cur] != -1 && hash[tree[cur]] != id)
{
hash[tree[cur]] = id;
v[e] = tree[cur];
next[e] = first[id];
first[id] = e;
++ e;
}
return ;
}
}
pushdown(cur);
if(mid >= s)
query(ls, x, mid, s, t, id);
if(mid + 1 <= t)
query(rs, mid + 1, y, s, t, id);
}
void color(int cur, int x, int y, int s, int t, int c)
{
int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
if(x >= s && y <= t)
{
tree[cur] = to[cur] = c;
return ;
}
pushdown(cur);
if(mid >= s)
color(ls, x, mid, s, t, c);
if(mid + 1 <= t)
color(rs, mid + 1, y, s, t, c);
update(cur);
}
void solve()
{
int i, j, k, l, ra, rb, ans = 0;
e = 0;
memset(hash, -1, sizeof(hash[0]) * N);
memset(first, -1, sizeof(first[0]) * N);
for(i = 0; i < N; i ++)
{
query(1, 0, D, seg[i].y1 << 1, seg[i].y2 << 1, seg[i].id);
color(1, 0, D, seg[i].y1 << 1, seg[i].y2 << 1, seg[i].id);
}
for(i = 0; i < N; i ++)
for(j = first[i]; j != -1; j = next[j])
for(k = first[i]; k != -1; k = next[k])
for(l = first[v[j]]; l != -1; l = next[l])
if(v[k] == v[l])
++ ans;
/*
for(i = 0; i < N; i ++)
{
A = 0;
for(k = first[i]; k != -1; k = next[k])
a[A ++] = v[k];
qsort(a, A, sizeof(a[0]), cmpid);
for(j = 0; j < A; j ++)
{
B = 0;
for(k = first[a[j]]; k != -1; k = next[k])
b[B ++] = v[k];
qsort(b, B, sizeof(b[0]), cmpid);
for(ra = rb = 0; ra < A && rb < B;)
{
if(a[ra] == b[rb])
++ ans;
if(a[ra] <= b[rb])
++ ra;
else
++ rb;
}
}
}
*/
printf("%d\n", ans);
}
int main()
{
int t;
scanf("%d", &t);
while(t --)
{
init();
solve();
}
return 0;
}