钦妹的苹果树(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.in与 appletree/appletree2.ans。
【样例 3】
见选手目录下的 appletree/appletree3.in与 appletree/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.