《算法竞赛进阶指南》0x43线段树 扫描线算法 POJ2482
Posted randy-lo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《算法竞赛进阶指南》0x43线段树 扫描线算法 POJ2482相关的知识,希望对你有一定的参考价值。
题目链接:http://poj.org/problem?id=2482
给出每个点框定的区域,求区域叠加的最大值,可以通过如下算法:
将每个可行点都标记,记录这些点上的权值,维护一个叶结点是一个权值点的线段树,更新的时候注意,由于所有的点都是可行点,所以右边界要在最后删除,遇到同样的x坐标的,优先叠加左边界的权值,然后去除结束矩形的权值。
代码:
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int maxn = 10010; struct node{ int l,r; int ans,add; }t[maxn<<3]; struct P{ unsigned int x,y1,y2; int c; bool operator < (const P& a)const { return x<a.x || (x==a.x && c>a.c); } }a[maxn<<1]; unsigned int b[maxn<<1]; int n; int num; unsigned int w,h; void build(int rt,int l,int r){ t[rt].l=l; t[rt].r=r; t[rt].add=0; t[rt].ans=0; if(l==r)return ; int mid=l+r>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); } void pushdown(int rt){ if(t[rt].add){ t[rt<<1].add+=t[rt].add; t[rt<<1|1].add+=t[rt].add; t[rt<<1].ans+=t[rt].add; t[rt<<1|1].ans+=t[rt].add; t[rt].add=0; } return ; } void update(int rt,int L,int R,int C){ if(L<=t[rt].l && t[rt].r<=R){ t[rt].ans+=C; t[rt].add+=C; return ; } pushdown(rt); int mid=(t[rt].l+t[rt].r)>>1; if(L<=mid)update(rt<<1,L,R,C); if(R>mid)update(rt<<1|1,L,R,C); t[rt].ans=max(t[rt<<1].ans,t[rt<<1|1].ans); } int get(unsigned int x){ return lower_bound(b+1,b+num+1,x)-b; } void solve(){ unsigned int x,y; int c; for(int i=1;i<=n;i++){ int k=i<<1; scanf("%u%u%d",&x,&y,&c); a[k-1].x=x,a[k-1].y1=y,a[k-1].y2=y+h-1,a[k-1].c=c; a[k].x=x+w-1,a[k].y1=y,a[k].y2=y+h-1,a[k].c=-c; b[k-1]=y; b[k]=y+h-1; } sort(b+1,b+2*n+1); num=unique(b+1,b+2*n+1)-(b+1); sort(a+1,a+2*n+1); build(1,1,num); int ans=0; for(int i=1;i<=2*n;i++){ int y1=get(a[i].y1); int y2=get(a[i].y2); update(1,y1,y2,a[i].c); ans=max(ans,t[1].ans);//t[1]中保存了扫描段中的最大值 } cout<<ans<<endl; } int main(){ while(cin>>n>>w>>h)solve(); return 0; }
以上是关于《算法竞赛进阶指南》0x43线段树 扫描线算法 POJ2482的主要内容,如果未能解决你的问题,请参考以下文章
《算法竞赛进阶指南》-AcWing-97. 约数之和 Sumdiv-题解