题目链接:http://poj.org/problem?id=3277
这个题目算是我真正意义上做的第一个离散化和线段树结合的题目,做了很长时间,不断打补丁最终才AC,从这个题目中我学到了很多
1、离散化的思想
2、线段树的数组下标建树方式(以前全部都是在数组上用指针建立树)
3、L>>1+1是先做1+1,也就是说L>>1+1 <==> L>>2 ,被这个东西坑了好长时间,所以不十分熟悉的运算符不要想当然啊
4、数组下标建立线段树在操作方便程度上和在对应操作情况下数组下标建立树的方式程序运行起来速度快些(不是数组下标快,而是操作简单了)
开始看这个题目始终没能理解离散化到底是怎么回事,不过现在明白了,也就是直线上那么多整数点,如果我们要一个单位的来建立线段树
不说超时了,内存你也开不了,考虑到给定的矩形数目有限,那么离散化,开始不理解离散化是没理解为什么这样就能行,现在懂了点,开
始先对所有线上的点排序,然后根据这些点来建立区间,想一下所有的矩形下边只会在这些点之间,也就是我么只需要给这些点从左到右编
号,然后建立线段树就可以了,接下来插入过程直接用二分查找找到矩形左右下标对应的编号然后更新这个区间就可以了,这个过程还是需
要好好理解的。
下面程序中我觉得这段代码还是需要解释下的:
if(re_root[root].L+1!=re_root[root].R && re_root[root].h !=-1)
re_root[root<<1].h=re_root[(root<<1)+1].h=re_root[root].h,re_root[root].h=-1;
上面代码是在插入过程中的往下拉的一段代码,当全这个大区间root,如果接下来的更新涉及到这个区间,而又不是整个区间
那么当前这个没更新的h就要往下拉,因为当前区间的某一段不是这个高度h了,那么就要向下拉然后把这个区间的h变成-1,
其实-1的意思就是告诉你查询的时候接着向下查询,这段区间要么没有矩形,要么就有高度不同的矩形(高度为0和高度不
为0的也算不同高度矩形)
在插入的时候对高度从小到大排序,这样在插入的时候会省事些,其实不排序也没什么大事!
数组下标建立线段树的AC代码(指针版改装):
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
#define maxn 440004
struct point
{
long long l,r,h;
}org[maxn];
struct node
{
long long L,R;
long long h;
}re_root[maxn];
long long n;
long long cut[maxn*3];
bool cmp1(const point &a,const point &b)
{
return a.h < b.h;
}
long long pos;
int build_tree(long long root,long long l,long long r)
{
re_root[root].L=l,re_root[root].R=r;
re_root[root].h=-1;
if(l+1==r)
return 0;
long long mid=(l+r)>>1;
build_tree(root<<1,l,mid);
build_tree((root<<1)+1,mid,r);//教训啊
return 0;
}
int find_num(long long l,long long r,long long num)
{
long long mid;
while(l<=r)
{
mid=(l+r)>>1;
if(cut[mid]==num)
return mid;
if(cut[mid]>num)
r=mid-1;
else
l=mid+1;
}
return 0;
}
int insert(long long root,long long l,long long r,long long num)
{
if(num <= re_root[root].h)
return 0;
if(re_root[root].L==l && re_root[root].R==r)
{
re_root[root].h=num;
return 0;
}
if(re_root[root].L+1!=re_root[root].R && re_root[root].h !=-1)
re_root[root<<1].h=re_root[(root<<1)+1].h=re_root[root].h,re_root[root].h=-1;
if(re_root[root].L+1==re_root[root].R)
return 0;
long long mid=(re_root[root].L + re_root[root].R)>>1;
if(r <= mid)
insert(root<<1,l,r,num);
else if(l>=mid)
insert((root<<1)+1,l,r,num);
else
insert(root<<1,l,mid,num),insert((root<<1)+1,mid,r,num);
return 0;
}
long long find_ans(long long root)
{
if(re_root[root].h!=-1)
{
// printf("%lld %lld %lld\n",cut[re_root[root].R],cut[re_root[root].L],re_root[root].h);
return ((long long)(cut[re_root[root].R]-cut[re_root[root].L])*re_root[root].h);
}
if(re_root[root].L+1 == re_root[root].R)
return 0;
long long mid=(re_root[root].L+re_root[root].R)>>1;
return find_ans(root<<1)+find_ans((root<<1)+1);
}
int main()
{
long long i,j,k,r,l;
while(scanf("%lld",&n)!=EOF)
{
k=0;
pos=1;
for(i=0;i<n;i++)
{
scanf("%lld%lld%lld",&org[i].l,&org[i].r,&org[i].h);
cut[k++]=org[i].l,cut[k++]=org[i].r;
}
sort(cut,cut+k);
sort(org,org+n,cmp1);
r=1;
for(i=1;i<k;i++)
if(cut[i]!=cut[i-1])
cut[r++]=cut[i];
k=r;
build_tree(1,0,k-1);
for(i=0;i<n;i++)
{
l=find_num(0,k-1,org[i].l);
r=find_num(0,k-1,org[i].r);
insert(1,l,r,org[i].h);
}
printf("%lld\n",find_ans(1));
}
return 0;
}
指针的TLE代码:
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
#define maxn 440004
struct point
{
long long l,r,h;
}org[maxn];
struct node
{
long long L,R;
long long h;
node *left,*right;
}re_root[maxn];
long long n;
long long cut[maxn*3];
bool cmp1(const point &a,const point &b)
{
return a.h < b.h;
}
long long pos;
int build_tree(node *root)
{
if(root->L+1 == root->R)
return 0;
long long mid=(root->L+root->R)>>1;
root->left=&re_root[pos];
re_root[pos].h=-1,re_root[pos].L=root->L,re_root[pos++].R=mid;
build_tree(root->left);
root->right=&re_root[pos];
re_root[pos].L=mid,re_root[pos].R=root->R,re_root[pos++].h=-1;
build_tree(root->right);
return 0;
}
int find_num(long long l,long long r,long long num)
{
long long mid;
while(l<=r)
{
mid=(l+r)>>1;
if(cut[mid]==num)
return mid;
if(cut[mid]>num)
r=mid-1;
else
l=mid+1;
}
return 0;
}
int insert(node *root,long long l,long long r,long long num)
{
if(root->h >= num)
return 0;
if(root->L+1 == root->R)
{
root->h=num;
return 0;
}
if(root->L+1!=root->R && root->h !=-1)
root->left->h=root->right->h=root->h,root->h=-1;
long long mid=(root->L + root->R)>>1;
if(r <= mid)
insert(root->left,l,r,num);
else if(l>=mid)
insert(root->right,l,r,num);
else
insert(root->left,l,mid,num),insert(root->right,mid,r,num);
return 0;
}
long long find_ans(node *root)
{
if(root->h!=-1)
{
return ((long long)(cut[root->R]-cut[root->L])*root->h);
}
if(root->L+1 == root->R)
return 0;
long long mid=(root->L+root->R)>>1;
return find_ans(root->left)+find_ans(root->right);
}
int main()
{
long long i,j,k,r,l;
while(scanf("%lld",&n)!=EOF)
{
k=0;
pos=1;
for(i=0;i<n;i++)
{
scanf("%lld%lld%lld",&org[i].l,&org[i].r,&org[i].h);
cut[k++]=org[i].l,cut[k++]=org[i].r;
}
sort(cut,cut+k);
// sort(org,org+n,cmp1);
r=1;
for(i=1;i<k;i++)
if(cut[i]!=cut[i-1])
cut[r++]=cut[i];
k=r;
re_root[0].L=0,re_root[0].R=k-1,re_root[0].h=-1;
build_tree(&re_root[0]);
for(i=0;i<n;i++)
{
l=find_num(0,k-1,org[i].l);
r=find_num(0,k-1,org[i].r);
insert(&re_root[0],l,r,org[i].h);
}
printf("%lld\n",find_ans(&re_root[0]));//<<endl;
}
return 0;
}