poj 3368 离散化+线段树

本文介绍了如何利用离散化和线段树解决POJ 3368题目的区间众数查询问题。通过将连续相同元素的区间压缩为一个节点,然后针对三种不同查询情况进行讨论,实现快速求解。ZKW线段树的应用使得算法效率显著提高。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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. 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值