钦妹的苹果树

钦妹的苹果树(appletree)

 

【题目背景】

钦妹和弗雷兹姐姐是好朋友。

 

【题目描述】

钦妹和弗雷兹姐姐在 C 市有一棵 n 个节点的苹果树,节点的编号为 1 . . . n。顾名思义,它是一棵树,也就是说它是一张恰好有 n − 1 条无向边的连通图。

作为一棵苹果树,当然少不了苹果。树上的每个节点都会有无穷无尽的苹果,就如  俗话‘‘江之永矣,不可方思’’ 说的那样。

俗话说得好:‘‘橘生淮南则为橘,生于淮北则为枳’’,在不同节点上生长的苹果也有不同的特点(由于光照、到根的距离等因素)。苹果有 2 个属性:重量和甜度。近似地, 我们认为编号为 i 的节点上生长出的苹果甜度均为 si,重量均为 ti

作为一名贴心大姐姐,弗雷兹姐姐每天都会带着她的钦妹和其他小朋友在苹果树上漫步(?)。每天他们都会从树上的其中一个节点走到另一个节点,并顺路采摘一些苹果。  为了节省时间,弗雷兹姐姐一定会带领小朋友们走最短路(即经过尽可能少的边)。

包括钦妹在内的 K 位小朋友都带着一个麻袋。钦妹的麻袋最大,他的麻袋大小为

K。其他小朋友都是钦妹的粉丝,所以他们的麻袋大小分别是1, 2, . . . , K − 1。(大小为x 的麻袋能装下总重量不超过 x 的苹果)

特别地,弗雷兹姐姐要照顾钦妹和其他小朋友,所以她并没有带麻袋,也就不能摘  苹果回去了。

孩子们总想使自己得到的苹果的甜度总和最大。然而,由于小朋友们并不是最聪明,  所以他们经常捡了芝麻丢了西瓜,做出一些不优的采摘决策。有一天,又有许多小朋友没有按最优策略采摘,浪费了许多优秀的苹果。弗雷兹姐姐愧疚万分,伤心地哭了起来。大家看到这一幕,都不知如何是好。

这时,聪明的孩子王钦妹站了出来:‘‘我可以帮大家制定出最优的采摘方案!”

孩子们的长者丁爷爷目睹了这一切。他对钦妹的勇敢无比钦佩。但他还是担心钦妹  一时大意,算错了结果,这样丢了面子不说,还可能让弗雷兹姐姐更加伤心。于是,他  决定指派他的小弟 Yazid 也去进行同样的计算。

辣鸡蒟蒻 Yazid 手足无措,便向你请教。方便起见,你只需要输出每个小朋友能获得的最大甜度和的总和以及异或和即可。即假设麻袋大小为 i 的小朋友能够获得的最大甜度和为 resulti,那么你只需要求出 result1+ result2+ · · · + resultK result1 ⊕ result2 ⊕ · · · ⊕ resultK 即可。(其中 ⊕ 运算表示异或(xor)运算,即 C 或 C++ 语言中的ˆ运算符、Pascal 语言中的xor运算符对应的运算)

 

 

【输入格式】

从文件 appletree.in 中读入数据。

第一行 2 个正整数 n, K,分别表示苹果树的节点数和小朋友的总数(也同样对应了钦妹的麻袋大小)。

接下来 n − 1 行,每行 2 个正整数 u, v,表示苹果树上有一条连接 u, v 的双向道路。接下来一行 n 个用空格隔开的正整数 t1 . . . tn,依次描述节点 1 . . . n 上苹果的重量。接下来一行 n 个用空格隔开的正整数 s1 . . . sn,依次描述节点 1 . . . n 上苹果的甜度。接下来一行一个整数 Q,表示总天数。

接下来 Q 行,每行 2 个正整数 u, v 描述一天的漫步,表示这次漫步的起点为 u,终点为 v

 

【输出格式】

输出到文件 appletree.out 中。

对于每天的漫步,输出一行 2 个整数,分别表示这次漫步中,K 个小朋友最大甜度的总和以及异或和。

 

【样例 1 输入】

5 10

1 2

2 3

2 4

1 5

1 2 3 4 5

10 15 30 45 50

5

1 1

2 5

1 3

1 4

5 4

 

【样例 1 输出】

550 14

550 14

 

550 14

600 64

600 64

 【样例 2】

见选手目录下的 appletree/appletree2.inappletree/appletree2.ans

 【样例 3】

见选手目录下的 appletree/appletree3.inappletree/appletree3.ans

 【子任务】

对于 25% 的数据,保证 Q ≤310。

对于 45% 的数据,保证 n ≤310。

对于 70% 的数据,保证 n, Q ≤10, 000

对于 80% 的数据,保证 n, Q ≤25, 000,K ≤33。

对于另外 10% 的数据,保证所有的道路连接的节点的编号都是相邻的。对于 100% 的数据,保证 n, Q ≤ 40, 000,1 ≤ K ≤ 61。

对于 100% 的数据,保证 1 ≤ ti K,1≤ si ≤ 106。

题解:以每一个重量建一棵树,各个点的价值为节点用来求出最大值。我们将两个点用倍增求出LCA后在路径上对所有的树进行处理求出最大值。

Code:

{$M 20000000,0,maxlongint} 
var
  ans1,ans2:int64;cnt,u,v,n,k,q,i,j,a,b:longint;
  deep,vet,next,head,t,s,ans,maxk:array[0..80005] of longint;
  dp:array[0..40005,0..20,0..65] of longint;
  f:array[0..40005,0..20] of longint;
procedure add(u,v:longint);
begin
  inc(cnt);
  vet[cnt]:=v;
  next[cnt]:=head[u];
  head[u]:=cnt;
end;
function max(a,b:longint):longint;
begin
  if a>b then exit(a) else exit(b);
end;
procedure dfs(u,fa:longint);
var e,v,i,j:longint;
begin
  f[u,0]:=fa;
  dp[u,0,t[u]]:=max(dp[u,0,t[u]],s[u]);
  dp[u,0,t[fa]]:=max(dp[u,0,t[fa]],s[fa]);
  for i:=1 to 16 do
  begin
    f[u,i]:=f[f[u,i-1],i-1];
    for j:=1 to k do
      dp[u,i,j]:=max(dp[u,i-1,j],dp[f[u,i-1],i-1,j]);
  end;
  e:=head[u];
  while e<>0 do
  begin
    v:=vet[e];
    if v<>fa then
    begin
      deep[v]:=deep[u]+1;
      dfs(v,u);
    end;
    e:=next[e];
  end;
end;
procedure lca(x,y:longint);
var t,i,j:longint;
begin
  if deep[x]<deep[y] then
  begin
    t:=x;x:=y;y:=t;
  end;
  for i:=16 downto 0 do
    if deep[f[x,i]]>=deep[y] then
    begin
      for j:=1 to k do maxk[j]:=max(maxk[j],dp[x,i,j]);
      x:=f[x,i];
    end;
  if x=y then exit;
  for i:=16 downto 0 do
    if f[x,i]<>f[y,i] then
    begin
      for j:=1 to k do maxk[j]:=max(maxk[j],dp[x,i,j]);
      for j:=1 to k do maxk[j]:=max(maxk[j],dp[y,i,j]);
      x:=f[x,i];y:=f[y,i];
    end;
  for j:=1 to k do maxk[j]:=max(maxk[j],dp[x,0,j]);
  for j:=1 to k do maxk[j]:=max(maxk[j],dp[y,0,j]);
end;
begin
  assign(input,'appletree.in');reset(input);
  assign(output,'appletree.out');rewrite(output);
  readln(n,k);
  for i:=1 to n-1 do
  begin
    readln(u,v);
    add(u,v);add(v,u);
  end;
  for i:=1 to n do read(t[i]);
  for i:=1 to n do read(s[i]);
  dfs(1,0);
  readln(q);
  while q>0 do
  begin
    dec(q);
    readln(a,b);
    for i:=1 to k do
    begin
      ans[i]:=0;
      maxk[i]:=0;
    end;
    ans1:=0;ans2:=0;
    maxk[t[a]]:=s[a];
    maxk[t[b]]:=s[b];
    lca(a,b);
    for i:=1 to k do
      for j:=i to k do
        ans[j]:=max(ans[j],ans[j-i]+maxk[i]);
    for i:=1 to k do ans1:=ans1+ans[i];
    for i:=1 to k do ans2:=ans2 xor ans[i];
    writeln(ans1,' ',ans2);
  end;
  close(input);close(output);
end.

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JackflyDC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值