• POJ1436


    题目链接:https://vjudge.net/problem/POJ-1436

    解题思路:基于y轴建立线段树。

    如图是根据样例画出的图。下面都以题目样例为例。

    但是,如果仅仅以给出的y1, y2为边界的话会出现线段的最右点被当成一小段线段的问题,样例中的x=4的线段和x=1的线段会被判定“不可见”。为了方便处理边界情况,我们把y1和y2都乘2再存入线段树中,这也是用线段树解决问题的时候常用的处理边界争议的方法。

    在每次存入线段的时候,先检查一下已有的线段树,看看以我们要存入的线段的端点[y1,y2]为边界的线段上是否已有线段,如果有,以一个二维数组记录起来。最后以几个for循环来得出ans。

    注意:用bool型代替int型可节省很多空间。一开始那个link[ ][ ]数组我是用int型的,然后提交的时候一直MLE,后来看了网上的题解,知道了这个点,把int改成bool就AC了。

    AC代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int y=8000*2;
    const int maxn=8000+5;
    int tree[y<<2];
    bool link[maxn][maxn];
    struct side{
        int y1,y2,x;
        bool operator <(const side &a)const{
            return x<a.x;
        }
    }tmp[maxn];
    void pushdown(int rt){
        tree[rt<<1]=tree[rt<<1|1]=tree[rt];
        tree[rt]=-1;
    }
    void build(int L,int R,int x,int l,int r,int rt){
        if(L<=l&&r<=R){
            tree[rt]=x;
            return;
        }
        if(l==r)    return;
        if(tree[rt]!=-1)
            pushdown(rt);
        if(L<=(l+r)/2)    build(L,R,x,l,(l+r)/2,rt<<1);
        if((l+r)/2<R) build(L,R,x,(l+r)/2+1,r,rt<<1|1);
    }
    void query(int L,int R,int index,int l,int r,int rt){
        if(tree[rt]!=-1){
            link[tree[rt]][index]=true;
            return;
        }
        if(l==r)
            return;
        if(L<=(l+r)/2)    query(L,R,index,l,(l+r)/2,rt<<1);
        if((l+r)/2<R) query(L,R,index,(l+r)/2+1,r,rt<<1|1);
    }
    int main(){
        int n,ans;
        int d,i,j;
        scanf("%d",&d);
        while(d--){
            memset(tree,-1,sizeof(tree));
            memset(link,false,sizeof(link));
            scanf("%d",&n);
            for(i=0;i<n;i++)
                scanf("%d%d%d",&tmp[i].y1,&tmp[i].y2,&tmp[i].x);
            sort(tmp,tmp+n);
            for(i=0;i<n;i++){
                query(tmp[i].y1*2,tmp[i].y2*2,i,0,y,1);
                build(tmp[i].y1*2,tmp[i].y2*2,i,0,y,1);
            }
            ans=0;
            for(i=0;i<n;i++)
                for(j=i+1;j<n;j++){
                    if(link[i][j]){
                        for(int k=i+1;k<j;k++){
                            if(link[i][k]&&link[k][j])
                                ans++;
                        }
                    }
                }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    sobel
    构造函数
    #pragma once & ifnde
    #pragma comment
    SET容器
    重载[] int& operator[ ]( )
    仿函数 operator()()
    remove_if erase
    vector
    map
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/7110638.html
Copyright © 2020-2023  润新知