zoukankan      html  css  js  c++  java
  • hdu 3255 Farming

    线段树求体积并

    题意来自网上,懒得写了。。。。

    有一块田,上面有n个矩阵,每个矩阵对应一个权值,矩阵相交的部分取权值大的,问最后能获得多少值

    我们可以转换一下模型,将权值看成矩阵的高,那么题目就成了n个长方体求并,由于m只有3,所以我们可以枚举高度,在每个高度用扫描线做一次矩阵面积并,最后求和即可,最多只有3次扫描线

    (想象一下长方体,交错在一次,有高有低,怎么求出整个立体形的体积)

    注意一点,这题数据还是比较大的,用int很危险,不旦最终答案要__int64,中间的一些乘法是会溢出的,我就是用int,WA了好几次,后来把所有改为__int64就过了

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define MAX 150105
    #define lch(i) ((i)<<1)
    #define rch(i) ((i)<<1|1)
    
    struct rec{
        __int64 x1,y1,x2,y2,v;
    };
    struct segment{
        __int64 l,r,h,val;
    };
    struct tree{
        int l,r,cnt,sum;
        int mid()
        { return (l+r)>>1;  }
    };
    typedef struct rec rec;
    typedef struct segment segment;
    typedef struct tree tree;
    rec rr[MAX];
    segment ss[MAX];
    tree tt[MAX];
    __int64 pos[MAX]; //横坐标离散化
    __int64 v[MAX]; 
    int N,M; 
    
    int cmp_rec(rec a ,rec b)
    { return a.v < b.v; }
    int cmp_segment(segment a , segment b)
    { return a.h < b.h; }
    
    void input()
    {
        scanf("%d%d",&N,&M);
        for(int i=1; i<=M; i++) scanf("%I64d",&v[i]);
        for(int i=0; i<N; i++)
        {
            int k;
            scanf("%I64d%I64d%I64d%I64d%d",&rr[i].x1, &rr[i].y1, &rr[i].x2, &rr[i].y2, &k);
            rr[i].v=v[k];
        }
    }
    
    void build(int l ,int r ,int rt)
    {
        tt[rt].l=l; tt[rt].r=r; 
        tt[rt].cnt=0; tt[rt].sum=0;
        if(l==r) return ; //叶子
        int mid=tt[rt].mid();
        build(l, mid, lch(rt));
        build(mid+1, r, rch(rt));
    }
    
    int binary(int key ,int low, int high)
    {
        int mid;
        while(low<=high)
        {
            mid=(low+high)>>1;
            if(pos[mid]==key) return mid;
            else if(key < pos[mid]) high=mid-1;
            else low=mid+1;
        }
        return -1;
    }
    
    void cal(int rt)
    {
        if(tt[rt].cnt) 
            tt[rt].sum=pos[tt[rt].r+1]-pos[tt[rt].l];
        else if(tt[rt].l==tt[rt].r)
            tt[rt].sum=0;
        else 
            tt[rt].sum=tt[lch(rt)].sum + tt[rch(rt)].sum;
    }
    
    void updata(int l , int r , int val ,int rt)
    {
        if(tt[rt].l==l && tt[rt].r==r) //目标区间
        {
            tt[rt].cnt += val ; //更新覆盖情况
            cal(rt); //计算覆盖长度
            return ;
        }
        int mid=tt[rt].mid();
        if(r<=mid)
            updata(l,r,val,lch(rt));
        else if(l>mid)
            updata(l,r,val,rch(rt));
        else
        {
            updata(l,mid,val,lch(rt));
            updata(mid+1,r,val,rch(rt));
        }
        cal(rt);
    }
    
    __int64 solve(int nn)
    {
        int m=0;
        for(int i=nn; i<N; i++)
        {
            ss[m].l=rr[i].x1;   ss[m].r=rr[i].x2;   ss[m].h=rr[i].y1;   ss[m].val=1;
            ss[m+1].l=rr[i].x1; ss[m+1].r=rr[i].x2; ss[m+1].h=rr[i].y2; ss[m+1].val=-1;
            pos[m]=rr[i].x1;    pos[m+1]=rr[i].x2;
            m+=2;
        }
        sort(pos,pos+m); //对横坐标排序
        sort(ss,ss+m,cmp_segment); //对矩形的上下边按高度排序
        int mm=1;
        for(int i=1; i<m; i++) //pos数组去重
            if(pos[i]!=pos[i-1])
                pos[mm++]=pos[i];
        //ss数组的长度为m,pos去重后长度为mm
        //以[1,mm]来构建线段树,但是注意是点不是段
        
        build(0,mm-1,1);
        __int64 ans=0,res=0;
        for(int i=0; i<m-1; i++) //扫描到倒数第二条边界即可
        {
            int l=binary(ss[i].l,0,mm-1);    //查找出在线段树对应的区间
            int r=binary(ss[i].r,0,mm-1)-1;  
            //if(l>r)
            //{
                //res += tt[1].sum * (ss[i+1].h-ss[i].h);
                //continue;
            //}
            if(l<=r) updata(l,r,ss[i].val,1);
            res += tt[1].sum * (ss[i+1].h-ss[i].h);
        }
        return res;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        for(int t=1; t<=T; t++)
        {
            input();
            sort(rr,rr+N,cmp_rec);
    
            int s[MAX],kk;
            s[1]=0; kk=1;
            for(int i=1; i<N; i++) 
                if(rr[i].v!=rr[i-1].v)
                    s[++kk]=i;
            //将不同权值的矩形划分开来了
            
            __int64 ans=0,res;
            for(int k=1; k<=kk; k++) //对s[k]到n-1的矩形求一次面积并
            {
                res=solve(s[k]);
                if(k==1) ans += res * rr[s[k]].v;
                else     ans += res * ( rr[s[k]].v - rr[s[k-1]].v );
            }
            printf("Case %d: %I64d\n",t,ans);
        }
        return 0;
    }
  • 相关阅读:
    通过Http接口及SolrNet 两种方法基于Solr5.5.1 实现CURD
    Solr5.5.1 IK中文分词配置与使用
    windows环境tomcat8配置Solr5.5.1
    初谈SQL Server逻辑读、物理读、预读
    C#6新特性,让你的代码更干净
    PJAX初体验(主要是利用HTML5 新增API pushState和replaceState+AJAX)
    js实现String.Fomat
    iOS 画虚线
    UIFont字体大全
    iOS 里RGB 配色 UIColor colorWithRed
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2979472.html
Copyright © 2011-2022 走看看