HDU 5091 Beam Cannon

复习了一下线段树,才发现线段树还是做的太少了,好多都忘了

线段树主要有以下功能:RMQ,区间总和查询,单点更新,区间更新

都忘了区间更新时要延迟更新了,这里一开始WA了。

再说说这题的思路:

把每个点作为矩形的左下角,画出所有矩形,以被矩形覆盖次数最多的区域中的任一点作为矩形的右上角,即为我们要求的矩形。

也就是说,我们要求的是被矩形覆盖次数最多的次数,这样用扫描线就可以解决,但直接扫描过去的话要n^2复杂度,会超时,于是使用线段树

每扫描到一条边,即相当于对该点覆盖的y轴区间内所有值进行了一次更新,即区间更新,这样维护一个最大值就好了

#include<stdio.h> 
#include<algorithm>
using namespace std;
#define N 20005
struct Line{
	int x,y1,y2,flag;
}s[N];
int y[N];
int max(int a,int b){
	return a>b?a:b;
}
struct Node{
	int l,r,ma,add;
}node[N*4];
int cmp(Line a,Line b){
	if(a.x==b.x) return a.flag>b.flag;
	return a.x<b.x;
}
void Build(int cur,int l,int r){//[l,r) 
	node[cur].l=l;
	node[cur].r=r;
	node[cur].ma=0;
	node[cur].add=0;
	if(l==r){//当前结点为l 
		return;
	}
	int mid=(l+r)>>1;
	Build(cur*2,l,mid);
	Build(cur*2+1,mid+1,r);
}
void push_down(int cur){
	node[cur*2].add+=node[cur].add;//留给孙子结点的值 
	node[cur*2+1].add+=node[cur].add;
	node[cur*2].ma+=node[cur].add;
	node[cur*2+1].ma+=node[cur].add;
	node[cur].add=0;
}
void update(int cur,Line p){//要注意延迟更新,如果每一次都更新到叶结点的话复杂度就变成了n^2, 
	if(y[node[cur].l]>p.y2||y[node[cur].r]<p.y1) return;
	if(y[node[cur].l]>=p.y1&&y[node[cur].r]<=p.y2){
		node[cur].ma+=p.flag; 
		node[cur].add+=p.flag;//当前结点的add是需要给子结点加上的 
		return;
	}
	/*if(node[cur].l==node[cur].r) {
		return;//退化为某个点了,跳出 
	}*///这一句有前面的条件,不用写了,要么完全包含,要么完全不包含,其他的都要继续往下找 
	push_down(cur);
	int mid=(node[cur].l+node[cur].r)>>1;
	update(cur*2,p);
	update(cur*2+1,p);
	node[cur].ma=max(node[cur*2+1].ma,node[cur*2].ma);//能执行到这一步,说明子结点的值已经更新了 
}
int main(){
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	#endif
	int n,w,h;
	while(scanf("%d%d%d",&n,&w,&h)){
		if(n<0) break;
		int tmp1,tmp2;
		int cnt=1;
		int i;
		for(i=0;i<n;i++) {
			scanf("%d%d",&tmp1,&tmp2);
			s[cnt].x=tmp1;
			s[cnt].y1=tmp2;
			s[cnt].y2=tmp2+h;
			y[cnt]=tmp2;
			s[cnt++].flag=1;
			s[cnt].x=tmp1+w;
			s[cnt].y1=tmp2;
			s[cnt].y2=tmp2+h;
			y[cnt]=tmp2+h;
			s[cnt++].flag=-1;
		}
		sort(y+1,y+cnt);
		sort(s+1,s+cnt,cmp);
		int ycnt=unique(y+1,y+cnt)-y;
		Build(1,1,ycnt-1);
		int ans=0;
		for(i=1;i<cnt;i++){
			update(1,s[i]);
			ans=max(ans,node[1].ma);
		}
		
		printf("%d\n",ans);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值