PKU3277离散化+线段树

对于x坐标先进行一个排序 用一个数组记录它们是第几大 这样就把非常大的数压缩得很小 线段树中叶子节点记录的就是相邻x的区间
对于每个节点记录最高的h hcount代表这个区间有多少个高度 最后用每个区间宽度×h 在树中即可计算area
#include < stdio.h >
#include
< math.h >
#include
< string .h >
#include
< stdlib.h >
struct  node
{
    node 
* pl, * pr;
    
int iL, iR;
    
int height;
    
int hCount;
}
line[ 160008 ];

int  x1[ 40002 ], x2[ 40002 ];
int  x[ 80004 ];
int  xh[ 80004 ];
int  h[ 40002 ];
int  n;

int  lineCount;
__int64 area;

node 
*  newNode()
{
    node 
*pt = &line[lineCount++];
    memset(pt,
0,sizeof(node));
    
return pt;
}


node 
*  makeTree( int  i,  int  j)
{
    node 
* root=newNode();
    root
->iL=i;
    root
->iR=j;
    
if(j-i>1)
    
{
        
int mid=(i+j)/2;
        root
->pl=makeTree(i,mid);
        root
->pr=makeTree(mid,j);
    }

    
return root;
}


void  height(node  *  root,  int  h)
{
    root
->hCount=1;
    root
->height=h;
}


void  update(node  *  root,  int  x1,  int  x2,  int  h)
{
    
    
if(x[root->iL]==x1 && x[root->iR]==x2 && h > root->height)
    
{
        height(root,h);
        
return;
    }


    
if(root->iR - root->iL <= 1)
        
return;

    
if(root->hCount==1)
    
{
        
if(root->height >= h)
            
return;
        height(root
->pl,root->height);
        height(root
->pr,root->height);
    }


    root
->hCount=2;
    
if(root->height < h)root->height=h;

    
if(x[root->pl->iR]>x1)
    
{
        
if(x[root->pl->iR]>=x2)
            update(root
->pl, x1, x2, h);
        
else
        
{
            
int mid=(root->iL + root->iR)/2;
            update(root
->pl,x1,x[mid],h);
            update(root
->pr,x[mid],x2,h);
        }

    }

    
else
    
{
        update(root
->pr,x1,x2,h);
    }

    
}



void  count(node  *  root,  int  i,  int  j)
{
    
if(root->hCount==1)
    
{
        __int64 a, b;
        a
=x[root->iR]-x[root->iL];
        b
=root->height;
        area
+=a*b;
        
return;
    }

    
if(root->iR - root->iL <= 1 || root->hCount==0)
        
return;

    
if(root->pl->iR>i)
    
{
        
if(root->pl->iR>=j)
        
{
            count(root
->pl,i,j);
        }

        
else
        
{
            
int mid=(root->iL+root->iR)/2;
            count(root
->pl,i,mid);
            count(root
->pr,mid,j);
        }

    }

    
else
    
{
        count(root
->pr,i,j);
    }

}



int  cmp (  const   void   * a ,  const   void   * b )
{
    
return *(int *)a - *(int *)b;
}


int  main()
{

    
while(scanf("%d"&n) ==1)
    
{
        memset(x,
0,sizeof(x));
        memset(x1,
0,sizeof(x1));
        memset(x2,
0,sizeof(x2));
        memset(xh,
0,sizeof(xh));
        memset(h,
0,sizeof(h));

        area
=0;
        
int i;
        
for(i=0;i<n;i++)
        
{
            scanf(
"%d%d%d",&x1[i],&x2[i],&h[i]);
            xh[
2*i]=x1[i];
            xh[
2*i+1]=x2[i];
        }


        qsort(xh,
2*n,sizeof(xh[0]),cmp);



        
int max_i=0;
        
for(i=0;i<2*n;i++)
            
if(xh[i]!=xh[i-1|| i==0)
                x[max_i
++]=xh[i];

/**//*        for(i=0;i<max_i;i++)
            printf("%d  ", x[i]);
        printf("\n");
*/


        lineCount
=0;

        node 
* root=makeTree(0,max_i-1);
        
for(i=0;i<n;i++)
        
{
            update(root,x1[i],x2[i],h[i]);
        }


        count(root,
0,max_i-1);

        printf(
"%I64d\n",area);

    }

    
return 0;
}

转载于:https://www.cnblogs.com/SQL/archive/2007/10/12/922507.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值