hdu 1542 Atlantis(线段树,扫描线之面积并)
2016-12-14 19:28
274 查看
点击查看原题
线段树练习+扫描线,搁置了很久的题,刚开始以为看懂了,今天想想手码一遍,结果GG,发现了很多忽略的问题,在这里总结一番.
扫描线的原理我就不写了,网上解释的很清楚,我只挑些容易忽略的地方来写。
首先是节点的意义:
此题这里以x轴作线段树,每次操作只有区间的增加,但是和正常的线段树不太一样的是节点的意义,这里的节点表示每个区间L~R,实际上是点(L)到点(R+1)之间的区间,即每个叶子i都是表示点(i)到点(i+1)的区间,所以pushup函数里sum【rt】=X【r+1】-X【l】,这点不要和其他的线段树搞错,而在大多线段树里面节点(L,R),其实把每个值(L~R)看成了一个区间的中心,其实也就代表了一个区间,并不是一个点,所以在写的时候要注意每个值代表什么。
其次是区间覆盖的长度和延迟标记的处理:
不同于不同线段树的地方就是标记的更新方法,在这里是用不到pushdown函数的,因为sum求的是一段区间的覆盖长度,并不是简单的区间累加和。 一旦延迟标记下传到孩子节点,下次访问时无法正确判断sum的值。所以我们直接省略pushdown函数,因为延迟标记下传与否不影响sum的求值。当区间更新时,直接通过延迟标记把此区间的sum求出来,然后更新父亲节点的sum值就行了。当然我看到也有大神用了pushdown函数写出来了,感觉比较麻烦,但是这种写法更加灵活。
代码:
线段树练习+扫描线,搁置了很久的题,刚开始以为看懂了,今天想想手码一遍,结果GG,发现了很多忽略的问题,在这里总结一番.
扫描线的原理我就不写了,网上解释的很清楚,我只挑些容易忽略的地方来写。
首先是节点的意义:
此题这里以x轴作线段树,每次操作只有区间的增加,但是和正常的线段树不太一样的是节点的意义,这里的节点表示每个区间L~R,实际上是点(L)到点(R+1)之间的区间,即每个叶子i都是表示点(i)到点(i+1)的区间,所以pushup函数里sum【rt】=X【r+1】-X【l】,这点不要和其他的线段树搞错,而在大多线段树里面节点(L,R),其实把每个值(L~R)看成了一个区间的中心,其实也就代表了一个区间,并不是一个点,所以在写的时候要注意每个值代表什么。
其次是区间覆盖的长度和延迟标记的处理:
不同于不同线段树的地方就是标记的更新方法,在这里是用不到pushdown函数的,因为sum求的是一段区间的覆盖长度,并不是简单的区间累加和。 一旦延迟标记下传到孩子节点,下次访问时无法正确判断sum的值。所以我们直接省略pushdown函数,因为延迟标记下传与否不影响sum的求值。当区间更新时,直接通过延迟标记把此区间的sum求出来,然后更新父亲节点的sum值就行了。当然我看到也有大神用了pushdown函数写出来了,感觉比较麻烦,但是这种写法更加灵活。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <stack> #include <map> #include <set> #include <vector> #include <queue> #define mem(p,k) memset(p,k,sizeof(p)); #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define inf 0x6fffffff #define LL long long #define MAXN 3000 using namespace std; int col[MAXN<<2]; double sum[MAXN<<2],X[MAXN]; struct Seg{ double l,r,h; int cur; Seg(){} Seg(double a,double b,double c,int d):l(a),r(b),h(c),cur(d){} bool operator <(const Seg &a)const{ return h<a.h; } }ss[MAXN]; void pushup(int rt,int l,int r){ if(col[rt]){ sum[rt]=X[r+1]-X[l];//这就是如何求区间覆盖长度的方法。 } else if(l==r)sum[rt]=0; else sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void update(int L,int R,int c,int l, int r,int rt){ if(l>=L&&r<=R){ col[rt]+=c; pushup(rt,l,r);//此处需要更新区间值,然后回溯时更新父节点。 return ; } int m=(l+r)>>1; if(L<=m)update(L,R,c,lson); if(R>m) update(L,R,c,rson); pushup(rt,l,r); } int main(){ int n,k,pp=0; while(cin>>n&&n){ double ans=0; k=0; mem(sum,0); mem(col,0); for(int i=0;i<n;i++){ double a,b,c,d; scanf("%lf%lf%lf%lf",&a,&b,&c,&d); X[k]=a; ss[k++]=Seg(a,c,b,1); X[k]=c; ss[k++]=Seg(a,c,d,-1); } sort(ss,ss+k); sort(X,X+k); int kk=1; for(int i=1;i<k;i++){ if(X[i]!=X[i-1])X[kk++]=X[i]; } for(int i=0;i<k-1;i++){ int l=lower_bound(X,X+kk,ss[i].l)-X; int r=lower_bound(X,X+kk,ss[i].r)-X-1; if(l<=r)update(l,r,ss[i].cur,0,kk-1,1); ans+=sum[1]*(ss[i+1].h-ss[i].h); } printf("Test case #%d\nTotal explored area: %.2lf\n\n",++pp,ans); } return 0; }
相关文章推荐
- 【线段树 面积并 扫描线】HDU - 1542 Atlantis
- HDU 1542 Atlantis(线段树+扫描线求面积并)
- HDU1542——Atlantis(扫描线,线段树,矩形面积并,离散化)
- hdu 1542 & poj 1151 Atlantis 线段树扫描线求矩形面积并
- 【HDU 1542】Atlantis 矩形面积并(线段树,扫描法)
- hdu 1542 Atlantis 面积并 线段树 扫描线
- poj 1151 Atlantis / hdu 1542 线段树扫描线 矩形面积并
- HDU 1542 Atlantis(离散化+扫描线(求并面积)+线段树)
- HDU1542 Atlantis(扫描线+矩形面积并+线段树)
- hdu 1542&&poj 1151 Atlantis[线段树+扫描线求矩形面积的并]
- hdu 1542 Atlantis(线段树进阶,扫描线,矩形面积并)
- HDU 1542 Atlantis (线段树扫描线求面积并)
- HDU 1542 Atlantis(线段树扫描线,面积并)
- hdu 1542 Atlantis (线段树求矩形面积并)
- hdu 1542 Atlantis(线段树 线性扫描)
- HDU 1542 Atlantis (线段树 + 扫描线 + 离散化)
- hdu 1542 Atlantis(线段树+扫描线——面积并)
- hdu1542 Atlantis【矩形面积并+线段树】
- Hdu 1542 Atlantis 线段树 求矩形面积并
- hdu 1542 Atlantis(线段树,扫描线)