poj 3368是我ZKW线段树入门的做的一道题目,关键是如何转化为RMQ的模型。
要注意到这到区间众数查询的特殊性——序列非降,所以我们将相同连续的一段区间压缩成一个节点,离散化处理,节点记录区间的左右端点。对应每一个询问,分3种情况讨论:
1.所查询的(x,y)属于同一节点(或说区间),那就简单了,直接输出包含元素的个数,即y-x+1;
2.(x,y)在相邻的两个区间中,在x到区间末尾的个数与y到区间末尾的个数中取max值;
3.(x,y)包含多个节点,在不完整的x,y区间中与x,y中间完整的区间中取元素max值。
使用ZKW树,速度相当滴快啊,自此本题完美解决!
const find=131071;
var
group:array[0..100005]of longint;
left,right:array[0..100005]of longint;
tree:array[0..262144]of longint;
i,k,s,t,q,x,y:longint;
m,n,ans:longint;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
procedure init(z,w:longint);
var k1:longint;
begin
z:=z+find;
tree[z]:=w;
k:=z shr 1;
while k>0 do
begin
k1:=tree[k];
tree[k]:=max(tree[k shl 1],tree[(k shl 1)+1]);
if tree[k]=k1 then break;
k:=k shr 1;
end;
end;
function ask(x1,y1:longint):longint;
var w:longint;
begin
x1:=x1+find-1;y1:=y1+find+1;w:=-maxlongint;
while not(x1 xor y1=1) do
begin
if x1 and 1=0 then if tree[x1+1]>w then w:=tree[x1+1];
if y1 and 1=1 then if tree[y1-1]>w then w:=tree[y1-1];
x1:=x1 shr 1;y1:=y1 shr 1;
end;
exit(w);
end;
begin
repeat
read(n); if n=0 then halt;
readln(m);
q:=-1000000;t:=0;
for i:=1 to n do
begin
read(x);
if x=q then group[i]:=t;
if x>q then
begin
right[t]:=i-1;
inc(t);
group[i]:=t;
left[t]:=i;q:=x;
init(t-1,right[t-1]-left[t-1]+1);
end;
end;
right[t]:=n;init(t,right[t]-left[t]+1);
for i:=1 to m do begin
readln(x,y);ans:=0;
if x>y then begin q:=x;x:=y;y:=q;end;
if group[x]=group[y] then ans:=y-x+1;
if group[y]-group[x]=1 then ans:=max(right[group[x]]-x+1,y-left[group[y]]+1);
if group[y]-group[x]>1 then
begin
s:=max(right[group[x]]-x+1,y-left[group[y]]+1);
q:=ask(group[x]+1,group[y]-1);
ans:=max(s,q);
end;
writeln(ans); end;
until false;
end.