第一道线段树.. 略难。 引用忘了哪看的一句话“10亿的的数据规模是任何数据结构都无能为力的,所以必须离散化”。因为略复杂我用class写的…yzhw牛说“线段树编程复杂度太高,一般用树狀数组或者STL set。不要class,class运行爆慢” 但是哥就是用class和链表过了,怎样!! 1200ms.. 不过后来看了一下Google到用Pascal的蒟蒻牛的代码,发现树狀数组果然好用!
hw给了我篇论文,我发现现在的程度知道了一个数据结构的意思&&一些优化比如“lazy”,写出来的东西details上面大家都差不多的。比如这道题目的lazy我也是加了个-1作标签说明下面的节点需要递归确认,即这一块不是一大块一样的
优化有二:
1. compress() 每次插入完一个building以后沿着树往下看有没有标记为-1但是左右子树height(toLoad)相等的,如果有合并左右子树。实践证明这个优化对这题的数据用处不大,反而拖到了1800ms…
2. 这个厉害了,没它我算5000的数据都要跑半分钟,而还有两组40000的数据,加了这优化4w的秒出。也是刚刚那篇里提到的“观察发现,线段树的建树、统计操作已难以再优化,但插入操作却任可以优化。由于一开始房子的高度无序,所以每次插入如果全部包含不能直接赋值,还需要向下递归左右子树。其实我们可以先将房子的高度排序,然后再依次插入,这样一旦全部包含就可以直接赋值,程序的效率大大提高。这样这道题就可以AC了。”
代码:
#include <stdio.h> #include <stdlib.h> #include <algorithm> using namespace std; struct Building { int s,e,h; }; int searchMap(int map[],int mapN,int value) { int p0=0,p1=mapN-1; while(p0<p1) { int mid=(p0+p1)/2; if(value==map[mid]) p0=p1=mid; if(value<map[mid]) p1=mid-1; if(value>map[mid]) p0=mid+1; } return p0; } class segmentTreeNode { public: int p0,p1; int toLoad; int mid() { return (p0+p1)/2; } segmentTreeNode *lChild,*rChild,*parent; segmentTreeNode(int p0__,int p1__) { toLoad=0; p0=p0__; p1=p1__; if(p0==p1-1) lChild=rChild=NULL; else { lChild=new segmentTreeNode(p0,mid()); lChild->parent=this; rChild=new segmentTreeNode(mid(),p1); rChild->parent=this; } } ~segmentTreeNode() { delete lChild; delete rChild; } void load(const int,const int,const int); void compress(); long long result(int map[]); }; void segmentTreeNode::load(const int p0__,const int p1__,const int height) { if(toLoad>=height) return; if(p0__==p0 && p1__==p1) { toLoad=height; return; } if(toLoad>=0) { lChild->toLoad=toLoad; rChild->toLoad=toLoad; } toLoad=-1; if(p0__<mid()) { int end=min(p1__,mid()); lChild->load(p0__,end,height); } if(p1__>mid()) { int start=max(p0__,mid()); rChild->load(start,p1__,height); } return; } void segmentTreeNode::compress() { if(toLoad==-1) { lChild->compress(); rChild->compress(); if(lChild->toLoad!=-1 && lChild->toLoad==rChild->toLoad) toLoad=lChild->toLoad; } } long long segmentTreeNode::result(int map[]) { if(toLoad>=0) return ((long long)map[p1]-map[p0])*toLoad; return lChild->result(map)+rChild->result(map); } int comp(const void *a,const void *b) { return *(int *)a-*(int *)b; } int comp2(const void *__a,const void *__b) { Building *a=(Building *)__a; Building *b=(Building *)__b; return a->h-b->h; } int main() { Building building[40000]; int buildingN; scanf("%d",&buildingN); int map[80000]; for(int i=0;i<buildingN;i++) { scanf("%d%d%d",&building[i].s,&building[i].e,&building[i].h); map[2*i]=building[i].s; map[2*i+1]=building[i].e; } qsort(map,2*buildingN,sizeof(int),comp); int p0=0,p1=0; while(p1<2*buildingN) { if(map[p1]==map[p0]) { p1++; continue; } map[++p0]=map[p1]; p1++; } int mapN=p0+1; segmentTreeNode tree(0,mapN-1); tree.parent=NULL; qsort(building,buildingN,sizeof(Building),comp2); for(int i=0;i<buildingN;i++) { int start=searchMap(map,mapN,building[i].s); int end=searchMap(map,mapN,building[i].e); int height=building[i].h; tree.load(start,end,height); //tree.compress(); } printf("%lld\n",tree.result(map)); return 0; }