(题外话:这题这是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.
View Code

 

posted on 2014-09-19 22:37  acphile  阅读(567)  评论(0编辑  收藏  举报