zoukankan      html  css  js  c++  java
  • POJ 3277 City Horizon(叶子节点为[a,a+1)的线段树+离散化)

    网上还有用unique函数和lowerbound函数离散的方法,可以百度搜下题解就有。

    这里给出介绍unique函数的链接:http://www.cnblogs.com/zhangshu/archive/2011/07/23/2115090.html

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <set>
    /*
    题意:
    给出一条直线上的矩形左右坐标和高度,求所有矩形并的面积。
    思路:
    这里处理没有跟以前的线段树一样,这里每个叶子节点代表的是区间[a,a+1),而不像以前的代表一个点(a,a);
    需要建立基本单位为线段的线段树,建法与以点为单位的线段树就一点点不同,具体见代码。这样可以方便在离散化后求一段区间间的长度
    
    由于A、B的值太大,需要离散。且不可能开那么大的数组,也就不能通过A、B直接获取他们的映射值。
    而只能通过他们映射的值来获取对应的A、B,用二分查找。
    由于最后求并的面积,为方便起见,可以先将矩形按高度从小到大排序,后面的覆盖前面的即可。
    
    在discuss里别人写的几个注意点:
    总算有点收获,总结以下几点
    1、离散的时候要用二分来查找映射值
    2、数据全部用long long 吧,比较保险
    3、数组开大点,因为一共有40000组数据,每组数据两个点,加起来也就是有大约80000个点,所以N要开到80000,存线段树的数组要开到4*N。
    4、题目的意思是要算矩形和,也就是说同一个线段上有多个高度的话,取最高的那个,再modify的时候,
       可以先对输入的数据根据高度从小到大排序,在接下来的操作中直接覆盖,这样就可以避免一些不必要的麻烦。
    
    
    */
    using namespace std;
    const int maxn=40010;
    int n;
    int cnt;
    long long vk[maxn*2]; //vk[i]=A,表示A映射的值为i,要通过二分查找,寻找A对应的映射值
    long long val[maxn*2];
    struct Tree{
        long long sum; //该区间的矩阵面积
        long long num; //该区间的矩阵高度
        bool lazy;
    }tree[maxn<<3];
    struct Node{
        long long a,b,h; //区间[a,b],以及高度h
        bool operator<(const Node tmp)const{
            return h<tmp.h;
        }
    }node[maxn];
    
    //二分查找k对应的映射值
    int binsearch(long long k){
        int l=0,r=cnt,mid;
        while(l<=r){
            mid=(l+r)>>1;
            if(vk[mid]==k)
                return mid;
            if(vk[mid]<k)
                l=mid+1;
            else
                r=mid-1;
        }
        return -1;  //肯定会查找的到,这里就是摆设
    }
    
    void build(int rt,int L,int R){
        tree[rt].sum=0;
        tree[rt].num=0;
        tree[rt].lazy=false;
        if(L+1==R)   //这才是重点啊,建立区间为[a,a+1)的叶子节点
            return;
        int mid=(L+R)>>1;
        build(rt<<1,L,mid);
        build(rt<<1|1,mid,R);  //右儿子:mid~R
    }
    
    void pushUp(int rt){
        tree[rt].sum=(tree[rt<<1].sum+tree[rt<<1|1].sum);
    }
    
    void pushDown(int rt,int L,int R){
        if(tree[rt].lazy){
            int lson=rt<<1,rson=rt<<1|1;
            int mid=(L+R)>>1;
            long long l1=vk[L],r1=vk[mid],l2=vk[mid],r2=vk[R],length1,length2;
            tree[lson].num=tree[rson].num=tree[rt].num;
            length1=r1-l1;length2=r2-l2; //左儿子对应的区间长度和右儿子对应的区间长度
            tree[lson].sum=length1*tree[rt].num;
            tree[rson].sum=length2*tree[rt].num;
            tree[lson].lazy=tree[rson].lazy=true;
            tree[rt].lazy=false;
        }
    }
    //L,R是节点rt的区间,l,r是要更新的区间目标
    void update(int rt,int L,int R,int l,int r,long long h){
        long long  left=vk[L],right=vk[R],length;
        if(l<=L && R<=r){
            tree[rt].num=h;
            length=right-left;
            tree[rt].sum=h*length;
            tree[rt].lazy=true;
            return;
        }
        pushDown(rt,L,R);
        int mid=(L+R)>>1;
        //注意两个if条件里面不能有等号
        if(l<mid)
            update(rt<<1,L,mid,l,r,h);
        if(r>mid)
            update(rt<<1|1,mid,R,l,r,h);
        //也可以下面注释的语句
        /*
        if(r<=mid)
            update(rt<<1,L,mid,l,r,h);
        else if(l>=mid)
            update(rt<<1|1,mid,R,l,r,h);
        else{
            update(rt<<1,L,mid,l,mid,h);
            update(rt<<1|1,mid,R,mid,r,h);
        }
        */
        pushUp(rt);
    }
    int main()
    {
        long long a,b,h;
        int idx=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%I64d%I64d%I64d",&a,&b,&h);
            node[i].a=a;
            node[i].b=b;
            node[i].h=h;
            val[idx++]=a;
            val[idx++]=b;
        }
        //离散化
        sort(val,val+idx);
        cnt=1;
        vk[cnt]=val[0];
        for(int i=1;i<idx;i++){
            if(val[i]==val[i-1])
                continue;
            vk[++cnt]=val[i];  //只不过这里建立的是映射————key
        }
    
        build(1,1,cnt);
        sort(node,node+n);
        int x,y;
        for(int i=0;i<n;i++){
            //二分查找,获取映射
            x=binsearch(node[i].a);
            y=binsearch(node[i].b);
    //printf("%I64d %I64d: %d %d
    ",node[i].a,node[i].b,x,y);
            update(1,1,cnt,x,y,node[i].h);
        }
        printf("%I64d
    ",tree[1].sum);
        return 0;
    }
  • 相关阅读:
    微分中值定理和泰勒展开
    Burnside引理与Polya定理
    递推关系和母函数
    cogs 1361. 树 线段树
    cogs 247. 售票系统 线段树
    cogs 176. [USACO Feb07] 奶牛聚会 dijkstra
    cogs 1672. [SPOJ 375] 难存的情缘 树链剖分套线段树 易错! 全博客园最长最详细的题解
    cogs 886. [USACO 4.2] 完美的牛栏 二分图 匈牙利算法
    cogs 1254. 最难的任务 Dijkstra + 重边处理
    cogs 364. [HDU 1548] 奇怪的电梯 Dijkstra
  • 原文地址:https://www.cnblogs.com/chenxiwenruo/p/3391240.html
Copyright © 2011-2022 走看看