【BZOJ2653】middle(主席树,二分)
题意:一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。
给你一个长度为n的序列s。
回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
其中a<b<c<d。
位置也从0开始标号。
我会使用一些方式强制你在线。
n<=20000,Q<=25000
思路:RYZ上课讲的题,第一次做这种类型的主席树,以前只会序列第K大,树上第K大,维护二维前缀和之类的……
这道题的精髓是用主席树保存每个点被更改后的N个版本
对于一段区间与一个数X,如果区间中的数a[i]>=x则b[i]=1,否则-1
易得:若某一段中b[i]总和>=0则必定可以从其中取出一段中位数为X的序列,则X可以作为答案
反之显然答案具有单调性,子段和最大的一段一定可以构造出最大的中位数
查询时判断queryr(a,b)+querysum(b+1,c-1)+queryl(c,d)是否>=0即可
剩下的二分X与最大子段和,最大左右子段和维护部分已经在各种各样的地方(NOI Plus模拟赛)做了不下10遍了
而且还有各种写法不同难度的,比如暴力,RMQ之类的
这题就是单点修改+线段树版本的
强制从0开始标号P党表示不爽
1 var t:array[0..8100000,0..1]of longint; 2 root,lx,rx,sum:array[0..8100000]of longint; 3 a,b,d:array[1..30000]of longint; 4 n,que,i,j,cnt,l,r,last,lastans,mid:longint; 5 6 function max(x,y:longint):longint; 7 begin 8 if x>y then exit(x); 9 exit(y); 10 end; 11 12 procedure swap(var x,y:longint); 13 var t:longint; 14 begin 15 t:=x; x:=y; y:=t; 16 end; 17 18 procedure qsort(l,r:longint); 19 var i,j,mid:longint; 20 begin 21 i:=l; j:=r; mid:=a[(l+r)>>1]; 22 repeat 23 while mid>a[i] do inc(i); 24 while mid<a[j] do dec(j); 25 if i<=j then 26 begin 27 swap(a[i],a[j]); 28 swap(b[i],b[j]); 29 inc(i); dec(j); 30 end; 31 until i>j; 32 if l<j then qsort(l,j); 33 if i<r then qsort(i,r); 34 end; 35 36 procedure sort; 37 var i,j:longint; 38 begin 39 for i:=1 to 3 do 40 for j:=1 to 4-i do 41 if d[j]>d[j+1] then swap(d[j],d[j+1]); 42 end; 43 44 procedure pushup(p:longint); 45 var l,r:longint; 46 begin 47 l:=t[p,0]; r:=t[p,1]; 48 lx[p]:=max(lx[l],sum[l]+lx[r]); 49 rx[p]:=max(rx[r],sum[r]+rx[l]); 50 sum[p]:=sum[l]+sum[r]; 51 end; 52 53 procedure build(var p:longint;l,r:longint); 54 var mid:longint; 55 begin 56 inc(cnt); p:=cnt; 57 if l=r then 58 begin 59 lx[p]:=1; rx[p]:=1; sum[p]:=1; 60 exit; 61 end; 62 mid:=(l+r)>>1; 63 build(t[p,0],l,mid); 64 build(t[p,1],mid+1,r); 65 pushup(p); 66 end; 67 68 procedure update(l,r:longint;var p:longint;v,x:longint); 69 var mid:longint; 70 begin 71 inc(cnt); t[cnt]:=t[p]; lx[cnt]:=lx[p]; rx[cnt]:=rx[p]; sum[cnt]:=sum[p]; 72 p:=cnt; 73 if l=r then 74 begin 75 sum[p]:=x; lx[p]:=x; rx[p]:=x; 76 exit; 77 end; 78 mid:=(l+r)>>1; 79 if v<=mid then update(l,mid,t[p,0],v,x) 80 else update(mid+1,r,t[p,1],v,x); 81 pushup(p); 82 end; 83 84 function querysum(l,r,x,y,p:longint):longint; 85 var mid,s:longint; 86 begin 87 if (l=x)and(r=y) then exit(sum[p]); 88 mid:=(l+r)>>1; 89 s:=0; 90 if y<=mid then s:=querysum(l,mid,x,y,t[p,0]) 91 else if x>mid then s:=querysum(mid+1,r,x,y,t[p,1]) 92 else s:=querysum(l,mid,x,mid,t[p,0])+ 93 querysum(mid+1,r,mid+1,y,t[p,1]); 94 exit(s); 95 end; 96 97 function queryleft(l,r,x,y,p:longint):longint; 98 var mid,s:longint; 99 begin 100 if (l=x)and(r=y) then exit(lx[p]); 101 mid:=(l+r)>>1; 102 s:=0; 103 if y<=mid then s:=queryleft(l,mid,x,y,t[p,0]) 104 else if x>mid then s:=queryleft(mid+1,r,x,y,t[p,1]) 105 else s:=max(queryleft(l,mid,x,mid,t[p,0]), 106 querysum(l,mid,x,mid,t[p,0])+ 107 queryleft(mid+1,r,mid+1,y,t[p,1])); 108 exit(s); 109 end; 110 111 function queryright(l,r,x,y,p:longint):longint; 112 var mid,s:longint; 113 begin 114 if (l=x)and(r=y) then exit(rx[p]); 115 mid:=(l+r)>>1; 116 s:=0; 117 if y<=mid then s:=queryright(l,mid,x,y,t[p,0]) 118 else if x>mid then s:=queryright(mid+1,r,x,y,t[p,1]) 119 else s:=max(queryright(mid+1,r,mid+1,y,t[p,1]), 120 querysum(mid+1,r,mid+1,y,t[p,1])+ 121 queryright(l,mid,x,mid,t[p,0])); 122 exit(s); 123 end; 124 125 function isok(k,a,b,c,d:longint):boolean; 126 var s:longint; 127 begin 128 s:=0; 129 if b+1<=c-1 then s:=querysum(0,n-1,b+1,c-1,root[k]); 130 s:=s+queryright(0,n-1,a,b,root[k]); 131 s:=s+queryleft(0,n-1,c,d,root[k]); 132 exit(s>=0); 133 end; 134 135 begin 136 137 read(n); 138 for i:=1 to n do 139 begin 140 read(a[i]); b[i]:=i; 141 end; 142 qsort(1,n); 143 144 build(root[0],0,n-1); 145 for i:=1 to n do 146 begin 147 root[i]:=root[i-1]; 148 update(0,n-1,root[i],b[i]-1,-1); 149 end; 150 read(que); 151 for i:=1 to que do 152 begin 153 for j:=1 to 4 do read(d[j]); 154 for j:=1 to 4 do d[j]:=(d[j]+lastans) mod n; 155 sort; 156 l:=0; r:=n; last:=0; 157 while l<=r do 158 begin 159 mid:=(l+r)>>1; 160 if isok(mid,d[1],d[2],d[3],d[4]) then begin last:=mid; l:=mid+1; end 161 else r:=mid-1; 162 end; 163 lastans:=a[last+1]; 164 writeln(lastans); 165 end; 166 167 end.
null