[POI2014]KUR-Couriers
静态主席树
题面大意就是给定一个区间\(l,r\),让你求出一个数字\(num\)的出现次数大于\(\frac{r-l+1}{2}\)。虽然是一个很显然的主席树裸题,不过怎么能卡我空间呢?
思路就是,出现次数大于一半肯定是绝对的。如果左儿子的权值已经大于\(\frac{r-l+1}{2}\),那么右儿子肯定小于\(\frac{r-l+1}{2}\)。也可能两边都等于\(\frac{r-l+1}{2}\),不过这样子就说明没有答案。
如果左儿子(或者右儿子)的权值大于\(\frac{r-l+1}{2}\),那么答案肯定在左子树中,这样就可以\(log\ n\)的时间求出答案。
\(Code\)
// luogu-judger-enable-o2 //没有说pascal不能开
// 注意空间
var
left,right,tree:array[-1..10010007] of longint; //分别为左儿子的位置,右儿子的位置,本节点的权值
root:array[-1..10010007] of longint; //每一个根的编号
recf:array[-1..1500007] of longint; //每一个数的编号,直接用桶来代替离散化
bucket:array[-1..5001007] of longint; //每一个编号所代表的数
i,j,n,m,cnt,now,fa,tail,num,l,r,find:longint;
condition:real; //满足要求,即为(r-l+1)/2,其实可以是整数
procedure Build(l,r,key:longint);
var
mid:longint;
begin
inc(cnt); //动态开点
tree[cnt]:=tree[fa]+1;
if l=r then
exit;
mid:=(l+r) div 2;
if key<=mid then //往左走
begin //记得全部都要往左
left[cnt]:=cnt+1; //左儿子一定是cnt+1(除了叶子结点)
right[cnt]:=right[fa];
fa:=left[fa];
Build(l,mid,key);
end;
if key>mid then //如上
begin
right[cnt]:=cnt+1;
left[cnt]:=left[fa];
fa:=right[fa];
Build(mid+1,r,key);
end;
end;
procedure Query(l,r:longint);
var
mid,value:longint;
begin
if l=r then
begin
find:=bucket[l];
exit;
end;
value:=tree[left[fa]]-tree[left[now]]; //左边的权值
mid:=(l+r) div 2;
if value>condition then //满足
begin
fa:=left[fa];
now:=left[now];
Query(l,mid);
end;
value:=tree[right[fa]]-tree[right[now]]; //如上
if value>condition then
begin
fa:=right[fa];
now:=right[now];
Query(mid+1,r);
end;
end;
begin
read(n,m);
tail:=0;
for i:=1 to n do
begin
read(num);
if recf[num]=0 then //给予每一个数字编号
begin
inc(tail); //给予编号
recf[num]:=tail;
bucket[tail]:=num;
end;
root[i]:=cnt+1;
fa:=root[i-1];
Build(1,n,recf[num]); //往编号的位置插入,代替离散化。不过你是求区间第K大的话这样子是不行的
end;
for i:=1 to m do
begin
read(l,r);
condition:=(r-l+1)/2; //条件,小数类型
now:=root[l-1];
fa:=root[r];
find:=0;
Query(1,n);
writeln(find);
end;
end.
完结撒花!✿✿ヽ(゚▽゚)ノ✿