您的位置:首页 > 其它

【BZOJ2653】middle(主席树,二分)

2017-01-18 21:16 344 查看

题意:一个长度为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

:=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.

[p] 

 

 

 

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: