cf765F.Souvenirs

比赛的时候看错了C题于是不会做了……来搞F,听说有人莫队水过去了,于是也写了个莫队,TLE7……惨掉rating

editorial看得很烦躁啊……又回想起了被英语阅读支配的恐惧

离线,移动右端点,考虑维护左端点处的答案.设当前右端点移动到了i,数列为a[],则答案的更新一定是由a[i]与某些a[j](j<i)的差的绝对值引起的,下面只考虑a[j]≥a[i]的情况,a[j]≤a[i]同理(当然如果有a[j]=a[i]会被用来更新2次但是肯定不会影响答案正确性)

首先我们找出最大的一个j满足j<i,a[j]≥a[i],用它更新[1,j]的答案。设a[j]=y,那么在[1,j-1]中如果有a的值大于y,肯定不会对答案构成影响(因为它与a[i]的差大于a[j]-a[i]),实际上,我们发现对于a数列中任何一个位于[1,j-1]的数,当且仅当它处于[a[i],(a[i]+a[j])/2]时,才可能与a[i]成对,对前面的答案造成影响,如果一个元素的值位于((a[i]+a[j])/2,a[j]],那么它肯定会与a[j]成对。这样一来,我们就把需要考虑的值域从[a[i],1e9]缩短到了[a[i],(a[i]+a[j])/2],重复这个过程,每次都至少会把这个区间折半,于是更新答案的次数是O(log(1e9))的,更新答案的过程用一个区间取min的线段树维护,寻找某一值域中最右元素可用一个动态开点的权值线段树维护,于是总时间复杂度为O(nlog2MaxV+mlogn),如果把a[]离散化之后开权值线段树可以做到O(nlognlogMaxV+mlogn),其中MaxV=1e9.

  1 program cf765F;
  2 uses math;
  3 const maxn=100000+10;
  4       maxm=300000+10;
  5       maxv=1000000000;
  6 type query=record next,l,r:longint;end;
  7 var a,last:array[0..maxn] of longint;
  8     ques:array[0..maxm] of query;
  9     ans:array[0..maxm] of longint;
 10     mark:array[0..maxn*4] of longint;
 11     segv:array[0..maxn*40] of record l,r,right:longint;end;
 12     n,m,root,tot,i,j,l,r,id:longint;
 13 procedure build(x,l,r:longint);
 14 var mid:longint;
 15 begin
 16   mark[x]:=maxv+1;
 17   if l<r then
 18   begin
 19     mid:=(l+r)shr 1;
 20     build(x+x,l,mid);
 21     build(x+x+1,mid+1,r);
 22   end;
 23 end;
 24 procedure update(x,l,r,nowl,nowr,v:longint);
 25 var mid:longint;
 26 begin
 27   if(nowl<=l)and(r<=nowr) then
 28   begin
 29     mark[x]:=min(mark[x],v);
 30     exit;
 31   end;
 32   mid:=(l+r)shr 1;
 33   if nowl<=mid then update(x+x,l,mid,nowl,nowr,v);
 34   if nowr>mid then update(x+x+1,mid+1,r,nowl,nowr,v);
 35 end;
 36 function ask(x,l,r,p:longint):longint;
 37 var mid:longint;
 38 begin
 39   if l=r then exit(mark[x]);
 40   mid:=(l+r)shr 1;
 41   if p<=mid then exit(min(mark[x],ask(x+x,l,mid,p)))
 42     else exit(min(mark[x],ask(x+x+1,mid+1,r,p)));
 43 end;
 44 function findright(x,l,r,nowl,nowr:longint):longint;
 45 var mid:longint;
 46 begin
 47   if((nowl<=l)and(r<=nowr))or(x=0) then exit(segv[x].right);
 48   mid:=(l+r)shr 1;
 49   if nowr<=mid then exit(findright(segv[x].l,l,mid,nowl,nowr));
 50   if nowl>mid then exit(findright(segv[x].r,mid+1,r,nowl,nowr));
 51   exit(max(findright(segv[x].l,l,mid,nowl,nowr),findright(segv[x].r,mid+1,r,nowl,nowr)));
 52 end;
 53 procedure modify(var x:longint;l,r,p,v:longint);
 54 var mid:longint;
 55 begin
 56   if x=0 then
 57   begin
 58     inc(tot);
 59     x:=tot;
 60   end;
 61   segv[x].right:=max(segv[x].right,v);
 62   if l<r then
 63   begin
 64     mid:=(l+r)shr 1;
 65     if p<=mid then modify(segv[x].l,l,mid,p,v)
 66       else modify(segv[x].r,mid+1,r,p,v);
 67   end;
 68 end;
 69 begin
 70   readln(n);
 71   for i:=1 to n do read(a[i]);
 72   readln(m);
 73   for i:=1 to m do readln(ques[i].l,ques[i].r);
 74   fillchar(last,sizeof(last),0);
 75   for i:=1 to m do
 76   begin
 77     ques[i].next:=last[ques[i].r];
 78     last[ques[i].r]:=i;
 79   end;
 80   build(1,1,n);
 81   root:=0;
 82   tot:=0;
 83   segv[0].right:=0;
 84   for i:=1 to n do
 85   begin
 86     if i>1 then
 87     begin
 88       l:=a[i];
 89       r:=maxv;
 90       while true do
 91       begin
 92         id:=findright(root,0,maxv,l,r);
 93         if id=0 then break;
 94         update(1,1,n,1,id,a[id]-a[i]);
 95         if a[i]=a[id] then break;
 96         r:=(a[i]+a[id])shr 1;
 97       end;
 98       l:=0;
 99       r:=a[i];
100       while true do
101       begin
102         id:=findright(root,0,maxv,l,r);
103         if id=0 then break;
104         update(1,1,n,1,id,a[i]-a[id]);
105         if a[i]=a[id] then break;
106         l:=(a[i]+a[id])shr 1+1;
107       end;
108     end;
109     j:=last[i];
110     while j>0 do
111     begin
112       ans[j]:=ask(1,1,n,ques[j].l);
113       j:=ques[j].next;
114     end;
115     modify(root,0,maxv,a[i],i);
116   end;
117   for i:=1 to m do writeln(ans[i]);
118 end.
View Code

 

posted @ 2017-02-18 17:51 lkmcfj 阅读(...) 评论(...) 编辑 收藏