题目: | 二叉查找树 | |
来源: | Noi 2009 day1 第三题 | |
题目大意: | 神马权值,数据值,访问频率啰嗦一大堆,性质就类似treap,按照数据值排,再保 证权值。访问代价=访问频率*深度,可以花K代价来修改结点权值,从而导致树的结 构变化,求访问代价和与共修改代价的和最小 | |
数据范围: | N<=70,1<=K<=30000000 | |
样例: | 4 10 1 2 3 4 1 2 3 4 1 2 3 4 | 29 |
做题思路: | 动态规划 f(i,j,k)=min f(i,x-1,k)+f(x+1,j,k)+sum(i,j);x任意取 f(i,j,x)+k; x是[i,j]之间权值比k大的结点中最小的一个 然后,把这个树抽象了吧,既然数据值不能变,就按它排序,[l,r]表示l到r节点的树。 | |
知识点: | 动态规划,离散化 |
type
tre=record
d,c,p,num:longint;{<数据值,权值,访问频率,离散值>}
end;
var
tree:array[0..100]of tre;
b:array[0..400010]of longint;
f:array[0..100,0..100,0..100]of longint;
sum:array[0..100]of longint;
n,k,m,max,i:longint;
procedure qsort(l,r:longint);
var
i,j,k:longint;
t:tre;
begin
i:=l;j:=r;
k:=tree[(l+r)shr 1].d;
repeat
while tree[i].d<k do inc(i);
while tree[j].d>k do dec(j);
if i<=j then
begin
t:=tree[i];tree[i]:=tree[j];tree[j]:=t;
inc(i);dec(j);
end;
until i>j;
if i<r then qsort(i,r);
if j>l then qsort(l,j);
end;
functionmin(a,b:longint):longint;
begin
if a>b then exit(b);
exit(a);
end;
functiondfs(l,r,x:longint):longint;
var
i:longint;
begin
if f[l,r,x]<f[0,0,0] then exit(f[l,r,x]); {<记忆化>}
if l>r then
begin
f[l,r,x]:=0;
exit(0);
end;
for i:=l to r do
begin f[l,r,x]:=min(f[l,r,x],dfs(l,i-1,x)+dfs(i+1,r,x)+sum[r]-sum[l-1]+k);{<第二种情况>}
if tree[i].num>x then
begin
f[l,r,x]:=min(f[l,r,x],dfs(l,i-1,tree[i].num)+dfs(i+1,r,tree[i].num)+sum[r]-sum[l-1]);{<第一种情况>}
end;
end;
exit(f[l,r,x]); {<f[l,r,x]表示由l到r所有结点构成的子树,根节点权值<=x或者l,r之间权值比x大的最小的一个>}
end;
begin
assign(input,'treapmod.in');reset(input);
assign(output,'treapmod.out');rewrite(output);
fillchar(b,sizeof(b),0);
fillchar(sum,sizeof(sum),0);
fillchar(f,sizeof(f),63); {<63→无穷大>}
readln(n,k);
for i:=1 to n do read(tree[i].d);
max:=-maxlongint; {<找最大,离散化用>}
for i:=1 to n do
begin
read(tree[i].c);
b[tree[i].c]:=1;
if max<tree[i].c then max:=tree[i].c;
end;
for i:=1 to n do read(tree[i].p);
qsort(1,n); {<以下一小节是离散化,离散数据值>}
m:=0;
for i:=0 to max do
if b[i]>0 then
begin
inc(m);
b[i]:=m;
end;
for i:=1 to n do
begin
sum[i]:=sum[i-1]+tree[i].p; {<求访问频率和>}
tree[i].num:=b[tree[i].c]; {<返回离散化的值>}
end;
m:=maxlongint;
for i:=0 to 1 do
if m>dfs(1,n,i) then m:=f[1,n,i]; {<根节点变不变,去最小的一个>}
writeln(m);
close(input);close(output);
end.
题目来源:
http://www.rqnoj.cn/Problem_528.html