复习了一下线段树,才发现线段树还是做的太少了,好多都忘了
线段树主要有以下功能: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);
}
}