(题外话:这题这是ACMer的福利啊……)
我非常不擅长做矩形类的数据结构
一般来说,二维的问题我们要转化为一维来考虑
感觉一般的手法是对一维排序,并且线性扫描这一维,然后用各种数据结构维护另一维上的最优值
这道题我们首先对x排序,然后扫描x坐标
这时候我们要维护2条扫描线,一左一右(应该就是two pointer)
扫描线之间的长度就是要求小于等于窗口宽度
随着右扫描线的移动,我们把这条扫描线上的点加到某个数据结构中
随着左扫描线的移动,我们把这条扫描线的点删除
显然每个点添加一次且删除一次,要做O(n)次操作
下面我们要做的就是在给定的横坐标区域内,找出星星亮度和最大的窗口
显然这里横坐标区域中的每一个点我们都可以当作压缩在一条线上考虑
考虑求数列区间长度小于等于h的和的最大值,我们对于每一个位置x上的元素a[x]
在x+h的位置上加上-a[x],然后我们可以用线段树维护区间最大和
这个区间最大和长度一定是小于等于h的(想想为什么)
这里的线段树是单点修改,直接查询(难得不用lazy tag,但是要用lmax,rmax)
所以操作的复杂度为O(logn),查询O(1),总的复杂度为O(nlogn)
注意y的坐标很大,要离散化
1 var tree,lmax,rmax,maxx,c,rank:array[0..80010] of longint; 2 a:array[0..20010] of int64; 3 x,y,s:array[0..10010] of longint; 4 w,h,n,m,t,p,l,i,ans:longint; 5 6 function max(a,b:longint):longint; 7 begin 8 if a>b then exit(a) else exit(b); 9 end; 10 11 procedure swap(var a,b:longint); 12 var c:longint; 13 begin 14 c:=a; 15 a:=b; 16 b:=c; 17 end; 18 19 procedure sorty(l,r: longint); 20 var i,j: longint; 21 x,y:int64; 22 begin 23 i:=l; 24 j:=r; 25 x:=a[(l+r) shr 1]; 26 repeat 27 while a[i]<x do inc(i); 28 while x<a[j] do dec(j); 29 if not(i>j) then 30 begin 31 y:=a[i]; 32 a[i]:=a[j]; 33 a[j]:=y; 34 35 swap(c[i],c[j]); 36 inc(i); 37 j:=j-1; 38 end; 39 until i>j; 40 if l<j then sorty(l,j); 41 if i<r then sorty(i,r); 42 end; 43 44 procedure sortx(l,r: longint); 45 var i,j,z: longint; 46 begin 47 i:=l; 48 j:=r; 49 z:=x[(l+r) shr 1]; 50 repeat 51 while x[i]<z do inc(i); 52 while z<x[j] do dec(j); 53 if not(i>j) then 54 begin 55 swap(x[i],x[j]); 56 swap(y[i],y[j]); 57 swap(s[i],s[j]); 58 inc(i); 59 j:=j-1; 60 end; 61 until i>j; 62 if l<j then sortx(l,j); 63 if i<r then sortx(i,r); 64 end; 65 66 procedure work(i,l,r,x,z:longint); 67 var m:longint; 68 begin 69 if l=r then 70 begin 71 inc(tree[i],z); 72 lmax[i]:=tree[i]; 73 rmax[i]:=tree[i]; 74 maxx[i]:=tree[i]; 75 end 76 else begin 77 m:=(l+r) shr 1; 78 if x<=m then work(i*2,l,m,x,z) 79 else work(i*2+1,m+1,r,x,z); 80 inc(tree[i],z); 81 lmax[i]:=max(lmax[i*2],tree[i*2]+lmax[i*2+1]); //不多说 82 rmax[i]:=max(rmax[i*2+1],tree[i*2+1]+rmax[i*2]); 83 maxx[i]:=max(lmax[i*2+1]+rmax[i*2],max(maxx[i*2],maxx[i*2+1])); 84 end; 85 end; 86 87 begin 88 while not eof do 89 begin 90 readln(n,w,h); 91 for i:=1 to n do 92 readln(x[i],y[i],s[i]); 93 sortx(1,n); 94 //先对x排序,后面离散化y坐标对应就轻松一点 95 for i:=1 to n do 96 begin 97 a[i]:=y[i]; 98 a[i+n]:=int64(y[i])+int64(h);//当然y+h这个位置也要离散化 99 c[i]:=i; 100 c[i+n]:=i+n; 101 end; 102 t:=n*2; 103 sorty(1,t); 104 p:=1; 105 rank[c[1]]:=1; 106 for i:=2 to t do 107 begin 108 if (a[i]<>a[i-1]) then inc(p); 109 rank[c[i]]:=p; 110 end; 111 m:=p; 112 fillchar(tree,sizeof(tree),0); 113 fillchar(lmax,sizeof(lmax),0); 114 fillchar(rmax,sizeof(rmax),0); 115 fillchar(maxx,sizeof(maxx),0); 116 l:=1; 117 ans:=0; 118 for i:=1 to n do 119 begin 120 while (l<i) and (int64(x[l])+int64(w)<=x[i]) do 121 begin 122 work(1,1,m,rank[l],-s[l]); //删除左扫描线左边的点 123 work(1,1,m,rank[l+n],s[l]); 124 inc(l); 125 end; 126 work(1,1,m,rank[i+n],-s[i]); //右加入扫描线上的点 127 work(1,1,m,rank[i],s[i]); 128 ans:=max(ans,maxx[1]); 129 end; 130 writeln(ans); 131 end; 132 end.