标签:线段 break 复杂 find size 英语 modify one art
比赛的时候看错了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.
标签:线段 break 复杂 find size 英语 modify one art
原文地址:http://www.cnblogs.com/lkmcfj/p/6413726.html