POJ 1436

Horizontally Visible Segments
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 3240   Accepted: 1208

Description

There is a number of disjoint vertical line segments in the plane. We say that two segments are horizontally visible if they can be connected by a horizontal line segment that does not have any common points with other vertical segments. Three different vertical segments are said to form a triangle of segments if each two of them are horizontally visible. How many triangles can be found in a given set of vertical segments? 


Task 

Write a program which for each data set: 

reads the description of a set of vertical segments, 

computes the number of triangles in this set, 

writes the result. 

Input

The first line of the input contains exactly one positive integer d equal to the number of data sets, 1 <= d <= 20. The data sets follow. 

The first line of each data set contains exactly one integer n, 1 <= n <= 8 000, equal to the number of vertical line segments. 

Each of the following n lines consists of exactly 3 nonnegative integers separated by single spaces: 

yi', yi'', xi - y-coordinate of the beginning of a segment, y-coordinate of its end and its x-coordinate, respectively. The coordinates satisfy 0 <= yi' < yi'' <= 8 000, 0 <= xi <= 8 000. The segments are disjoint.

Output

The output should consist of exactly d lines, one line for each data set. Line i should contain exactly one integer equal to the number of triangles in the i-th data set.

Sample Input

1
5
0 4 4
0 3 1
3 4 2
0 2 2
0 2 3

Sample Output

1

Source

Central Europe 2001

经典的线段树 

题意是给你n条垂直线段,定义两条线段互相可见是指他们可以不经过任何一条直线被一条水平线相连,求有多少种三条线段两两互见的情况。可以转化为区间覆盖问题,有个trick:

问题:对于[1,4],[1,2],[3,4],[1,4]如果直接1-2,3-4覆盖,当用1-4query的时候,会发现不存在(2,3)区域的标记,
解决方法,每个点之间都插入一个点,用偶数表示原先的点,
用奇数表示点之间的区域,0,1,2,3,4   
                    0   1   2
然后读入数据 ,按横坐标从大到小排序 , 每次query去记录该线段向左看能看见的线段(存入vector),然后update修饰color表示区间覆盖,用used数组判重。最后n^4地去枚举所有互见边,找到三条两两互见,ans++;

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
///#define Online_Judge
#define outstars cout << "***********************" << endl;
#define clr(a,b) memset(a,b,sizeof(a))
#define lson l , m  , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define mk make_pair
#define FOR(i , x , n) for(int i = (x) ; i < (n) ; i++)
#define FORR(i , x , n) for(int i = (x) ; i <= (n) ; i++)
#define REP(i , x , n) for(int i = (x) ; i > (n) ; i--)
#define REPP(i ,x , n) for(int i = (x) ; i >= (n) ; i--)
const int MAXN = 8501 * 2;
const int sigma_size = 26;
const long long LLMAX = 0x7fffffffffffffffLL;
const long long LLMIN = 0x8000000000000000LL;
const int INF = 0x7fffffff;
const int IMIN = 0x80000000;
#define eps 1e-8
const int MOD = (int)1e9 + 7;
typedef long long LL;
const double PI = acos(-1.0);
typedef double D;
typedef pair<int , int> pi;
///#pragma comment(linker, "/STACK:102400000,102400000")
struct Seg_tree
{
    int left , right;
    int col ;
    int mid()
    {
        return (left + right) >> 1;
    }
}t[MAXN << 2];
struct Seg
{
    int left , right , pos;
}seg[MAXN];
bool cmp(const Seg &a , const Seg &b)
{
    return a.pos < b.pos;
}
int used[MAXN];
vector<int> edge[MAXN];
void build(int l , int r , int rt)
{
    t[rt].left = l;
    t[rt].right = r;
    t[rt].col = -1;
    if(l == r)return;
    int mid = t[rt].mid();
    build(l , mid , rt << 1);
    build(mid + 1 , r , rt << 1 | 1);
}
void PushDown(int rt)
{
    if(t[rt].col != -1)
    {
        t[rt << 1].col = t[rt << 1 | 1].col = t[rt].col;
        t[rt].col = -1;
    }
}
void update(int l , int r , int id ,int rt)
{
    if(l <= t[rt].left && r >= t[rt].right)
    {
        t[rt].col = id;
        return ;
    }
    PushDown(rt);
    int mid = t[rt].mid();
    if(l <= mid)update(l , r , id , rt << 1);
    if(r > mid)update(l , r , id , rt << 1 | 1);
}
void query(int l , int r , int id , int rt)
{
    if(t[rt].col != -1)
    {
        if(used[t[rt].col] != id)
        {
            edge[t[rt].col].push_back(id);
            used[t[rt].col] = id;
        }
        return;
    }
    if(t[rt].left == t[rt].right)return ;
    PushDown(rt);
    int mid = t[rt].mid();
    if(l <= mid)query(l , r, id , rt << 1);
    if(r > mid)query(l , r , id , rt << 1 | 1);
}
int main()
{
//    freopen("out.text" , "w" , stdout);
    int T;
    scanf("%d" , &T);
    while(T--)
    {
        int n;
        build(1 , MAXN , 1);
        scanf("%d" , &n);
        FOR(i , 0 , n)
        {
            scanf("%d%d%d" , &seg[i].left , &seg[i].right , &seg[i].pos);
            seg[i].left *= 2;
            seg[i].right *= 2;
            edge[i].clear();
        }
        sort(seg , seg + n , cmp);
        clr(used , -1);
        FOR(i , 0 , n)
        {
            query(seg[i].left , seg[i].right , i , 1);
            update(seg[i].left , seg[i].right , i , 1);
        }
        int ans = 0;
        FOR(i ,0 , n)
        {
            int m = edge[i].size();
            FOR(j , 0 , m)
            {
                int rt = edge[i][j];
                int mm = edge[rt].size();
                for(int k = j + 1 ; k < m ; k++)FOR(l , 0 , mm)
                {
                    if(edge[i][k] == edge[rt][l])ans++;
                }
            }
        }
        printf("%d\n" , ans);
    }
    return 0;
}


你可能感兴趣的:(线段树,ACM)