POJ1436 Horizontally Visible Segments

个人觉得比较坑的线段树的题目,因为题意我就理解了半天

题意:

有N根竖直的杆子,每个杆子都用一个长度,两根杆子可以想见意味着两个杆子在水平

方向上存在一条直线,使得该直线连接两个杆子,并且该水平直线和其他的杆子都没

交点,问一共有多少对三根杆子的组合使得杆子两两可见。这里要注意的地方有一点是如果只是两个杆子的边界相同,只要他们中间没有间隔他们也能相互看见,比如说y坐标为1——3和3——4是可以相互看见的,但是如果他们中间有一个2——3的杆子他们还是看不见,但是如果3——4的杆子在1——3和2——3之间那么还是没法阻挡,所以题意好坑。个人觉得不科学,也不符合实际。

解题思路就是把所有的线按x轴排序,然后依次向y轴映射,然后覆盖,

不过遇坑爹的边界设定,线段树的设计就要略有改进,也就是把所有的y值乘以2,这样的话就算1——3和2——3之间有3——4就会变为2——6,4——6,6——8那么实际上3——4它也只会覆盖6——8而不会将5覆盖保证了1——3和2——3之间的正常判定。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <cstdio>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
typedef long long LL;
using namespace std;
const int  mx = 16005;
int a[mx * 3];
bool ma[mx >> 1][mx >> 1];
int n,qr,ql,date;
struct K
{
    int l,r,x;
} S[mx];
bool cmp(K  a,K b)
{
    return a.x < b.x;
}
void update(int o = 1,int L = 0,int R = mx)
{
    if(ql <=  L && qr >= R)
    {
        a[o] = date;
//         printf("o = %d L =%d R = %d date =%d\n",o,L,R,date);
        return;
    }
    int mid = (R + L) >> 1;
    if(a[o] != 0)
    {
        a[o << 1] = a[o << 1 | 1] = a[o];
        a[o] = 0;
    }
//    printf("o = %d L =%d R = %d  ql = %d qr =%d date = %d mid = %d\n",o,L,R,ql,qr,date,mid);
    if(ql <= mid) update(o << 1,L,mid);
    if(qr > mid)  update(o << 1|1,mid + 1,R);
}
void qu(int o = 1,int L = 0,int R = mx)
{
//     printf("o = %d L =%d R = %d\n",o,L,R);
    if(a[o] != 0)
    {
//        printf("a[] = %d date =%d\n",a[o],date);
        ma[a[o]][date] = ma[date][a[o]] = true;
        return;
    }
    if(R == L) return;
//  printf("PPPPPP\n");
    int mid = (R + L) >> 1;
    if(ql <= mid) qu(o << 1,L,mid);
    if(qr > mid) qu(o << 1|1,mid + 1,R);
}
int main ()
{
    int T,i,h,k,g,j,ans;
    scanf("%d",&T);
    while (T--)
    {
        memset(a,0,sizeof(a));
        memset(ma,false,sizeof(ma));
        ans = 0;
        scanf("%d",&n);
        for(i = 1; i <= n; i++)
            scanf("%d%d%d",&S[i].l,&S[i].r,&S[i].x);
        sort(S + 1,S + n + 1,cmp);
        for(i = 1; i <= n; i++)
        {
            qr = S[i].r*2;
            ql = S[i].l*2;
            date = i;
            qu();
            update();
        }
        for(i = 1; i <= n; i++)
            for(j = i + 1; j <= n; j++)
                if(ma[i][j])
                    for(k = j; k <= n; k++)
                        if(ma[i][k] && ma[j][k])
                            ans++;
        printf("%d\n",ans);

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值