JIH的玩偶

题目描述
JIH的玩具厂设立以来,发展了一张销售关系网。这张网以玩具厂为总代理(根),构成一颗树。每个节点都代表一个客户,且每个节点都有重要度ai。JIH想将这些客户划成若干类别,当然同一类的客户重要度相差太大总是不妥。所以JIH决定先进行市场调研。JIH会选择两个客户X,从X向根走一共k个节点进行调查。调查的结果是这条路径上重要程度相差最大的两个客户的差值是多少。因为特殊需要,要求重要度大的客户必须在重要度小的客户后面(顺序为X到根,若序列为递减,则输出0,详情见样例)。
输入
第一行一个整数N 表示N个客户
第二行N个整数Ai 表示N个客户的重要程度(工厂是1)
第三行开始 共N-1行 每行2个整数 x,y 表示x的父亲是y
接着一行一个正整数Q,表示Q次调研
接着Q行,每行两个整数X,K。含义见题目表述。
输出
Q行,每行一个正整数,含义见题目描述。
样例输入
6
5 6 1 7 5 2
2 1
3 1
4 2
5 2
6 3
3
4 3
6 2
6 3
样例输出
0
0
4
提示
数据范围:
30% 的数据中N,Q<=1000
100%的数据中N,Q<=200000 Ai<=1000000

对于树上路径问题,我们采用倍增思想,记gmin[i,k],gmax[i,k],gans[i,k]分别表示i到i的2^k个父亲的最小值,最大值,与答案。对于答案的计算,对于预处理:
gans[i,k]:=max(gans[i,k-1],gans[f[i,k-1],k-1]);
gans[i,k]:=max(gans[i,k],gmax[f[i,k-1],k-1]-gmin[i,k-1]);
答案可能为两段答案的最大值,或者一段的最大值减另一段的最小值。
对于询问:
ans:=max(maxn-mini,max(gans[i,k],gans[j,k]));
答案可以是i到i+2^k这一段的gans,或j到j+2^k段的答案,或是i+2^k到j+2^k段的最大值-i到j段的最小值。

var
a:array[0..200022] of longint;
f,gmax,gmin,gans:array[0..200002,0..18] of longint;
n,i,u,v,k,q,x,r,jump,ans,mini,maxn,d:longint;
function max(a,b:longint):longint;
begin
  if a>b then exit(a) else exit(b);
end;

function min(a,b:longint):longint;
begin
  if a<b then exit(a) else exit(b);
end;

begin
  readln(n);
  for i:=1 to n do
    read(a[i]);
  readln;
  for i:=1 to n-1 do
  begin
    readln(v,u);
    f[v,0]:=u;
    gmax[v,0]:=max(a[v],a[u]);
    gmin[v,0]:=min(a[v],a[u]);
    gans[v,0]:=max(0,a[u]-a[v]);
  end;
  gmax[1,0]:=a[1];
  gmin[1,0]:=a[1];
  for k:=1 to 18 do
  begin
    for i:=1 to n do
    begin
      f[i,k]:=f[f[i,k-1],k-1];
      gmax[i,k]:=max(gmax[i,k-1],gmax[f[i,k-1],k-1]);
      gmin[i,k]:=min(gmin[i,k-1],gmin[f[i,k-1],k-1]);
      gans[i,k]:=max(gans[i,k-1],gans[f[i,k-1],k-1]);
      gans[i,k]:=max(gans[i,k],gmax[f[i,k-1],k-1]-gmin[i,k-1]);
    end;
  end;
  readln(q);
  for i:=1 to q do
  begin
    readln(u,x);
    x:=x-1;
    r:=0;
    for k:=18 downto 0 do
      if x>>k and 1=1 then begin r:=1<<k; break; end;
    ans:=0;
    jump:=x-r;
    v:=u;
    mini:=maxlongint;
    for d:=0 to 18 do
      if jump>>d and 1=1 then begin mini:=min(mini,gmin[v,d]); v:=f[v,d]; end;
    ans:=max(gans[u,k],gans[v,k]);
    v:=f[u,k];
    maxn:=0;
    for d:=0 to 18 do
      if jump>>d and 1=1 then begin maxn:=max(maxn,gmax[v,d]); v:=f[v,d]; end;
    ans:=max(maxn-mini,ans);
    writeln(ans);
  end;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值