poj 1436 Horizontally Visible Segments

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

 题意大概是:给出n条竖直线段,n行 y1,y2,x表示线段的y坐标和x坐标,问水平方向上3元组两两可见的组数。

 这题。。。简直无语了,狂TLE了一晚上,害得我不断优化,今天早上去掉了我写的那个“输入挂”,秒A了。(数据后面没'\n',我的挂写错了,判'\n'结束)。

  思路:按x坐标排序编号,从左往右,依次加入线段,加入之前,先统计它下面的可见线段(我是将此次线段push_back到下面的线段集合中,每次都是 小编号.push_back(大编号)且判重),然后update此线段的y坐标范围为此线段编号。 

            最后暴力查找。


#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#include <set>;
using namespace std;
typedef long long LL;
#define maxn 8010
int r[maxn],y1[maxn],y2[maxn],x[maxn];
int next[maxn];
vector<int>g[maxn];
int mak[maxn<<3];
int cmp(int a, int b)
{
    return x[a]<x[b];
}
bool found(int i,int x, int l, int r)
{
    int m;
    while(l<r)
    {
        m=(l+r)>>1;
        if(g[i][m]==x) return true;
        if(g[i][m]>x) r=m-1;
        else l=m+1;
    }
    return g[i][l]==x;
}
void pushdown(int rt)
{
    if(mak[rt])
    {
        mak[rt<<1]=mak[rt<<1|1]=mak[rt];
        mak[rt]=0;
    }
}
void update(int L, int R, int p, int l, int r, int rt)
{
    if(L<=l && R>=r)
    {
        mak[rt]=p;
        return;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,p,l,m,rt<<1);
    if(R>m)update(L,R,p,m+1,r,rt<<1|1);
    if(mak[rt<<1]&&mak[rt<<1]==mak[rt<<1|1])mak[rt]=mak[rt<<1];
}
void query(int L, int R, int p, int l, int r, int rt)
{
    if(mak[rt])
    {
        if(next[mak[rt]]==p)return;
        next[mak[rt]]=p;
        g[mak[rt]].push_back(p);
        return;
    }
    if(l==r)return;
    pushdown(rt);
    int m=(l+r)>>1;
    if(L<=m)query(L,R,p,l,m,rt<<1);
    if(R>m) query(L,R,p,m+1,r,rt<<1|1);
}
int main()
{
    int i,j,k,m,n;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int N=-1;
        scanf("%d",&n);
        memset(mak,0,sizeof(mak));
        memset(next,0,sizeof(next));
        for(i=1;i<=n;i++)
            {
                scanf("%d %d %d",y1+i,y2+i,x+i);
                y1[i]=y1[i]<<1|1,y2[i]=y2[i]<<1|1;
                if(N<y2[i])N=y2[i];
                r[i]=i;
                g[i].clear();
            }
        sort(r+1,r+1+n,cmp);
        for(i=1;i<=n;i++)
            j=r[i],
            query( y1[j],y2[j],i,1,N,1),
            update(y1[j],y2[j],i,1,N,1);
        int ans=0;
        int has[maxn];
        for(i=1;i<=n;i++)
        {
            int s=g[i].size();
            for(j=0;j<s;j++)
            {
                int a=g[i][j];
                int ss=g[a].size();
                for(k=0;k<ss;k++)
                    if(found(i,g[a][k],0,s-1))
                    ans++;
            }
        }
        printf("%d\n",ans);
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值