【树型DP】BZOJ1564 二叉查找树(noi2009)
標簽:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 二叉查找樹
【題目描述】
已知一棵特殊的二叉查找樹。根據定義,該二叉查找樹中每個結點的數據值都比它左兒子結點的數據值大,而比它右兒子結點的數據值小。
另一方面,這棵查找樹中每個結點都有一個權值,每個結點的權值都比它的兒子結點的權值要小。
已知樹中所有結點的數據值各不相同;所有結點的權值也各不相同。這時可得出這樣一個有趣的結論:如果能夠確定樹中每個結點的數據值和權值,那么樹的形態便可以唯一確定。因為這樣的一棵樹可以看成是按照權值從小到大順序插入結點所得到的、按照數據值排序的二叉查找樹。
一個結點在樹中的深度定義為它到樹根的距離加1。因此樹的根結點的深度為1。
每個結點除了數據值和權值以外,還有一個訪問頻度。我們定義一個結點在樹中的訪問代價為它的訪問頻度乘以它在樹中的深度。整棵樹的訪問代價定義為所有結點在樹中的訪問代價之和。
現在給定每個結點的數據值、權值和訪問頻度,你可以根據需要修改某些結點的權值,但每次修改你會付出K的額外修改代價。你可以把結點的權值改為任何實數,但是修改后所有結點的權值必須仍保持互不相同?,F在你要解決的問題是,整棵樹的訪問代價與額外修改代價的和最小是多少?
【輸入格式】
輸入文件中的第一行為兩個正整數N,K。其中:N表示結點的個數,K表示每次修改所需的額外修改代價。
接下來的一行為N個非負整數,表示每個結點的數據值。
再接下來的一行為N個非負整數,表示每個結點的權值。
再接下來的一行為N個非負整數,表示每個結點的訪問頻度。
其中:所有的數據值、權值、訪問頻度均不超過400000。每兩個數之間都有一個空格分隔,且行尾沒有空格。
【輸出格式】
輸出文件中僅一行為一個數,即你所能得到的整棵樹的訪問代價與額外修改代價之和的最小值。
【樣例輸入】
4 10
1 2 3 4
1 2 3 4
1 2 3 4
【樣例輸出】
29
分析:
參加比賽遇到的題目,比賽時看到題目感覺是用樹型dp,但一直沒有思路,只好用近似模擬的方法亂搞的,后來看了題解才會做......
首先我們知道該樹是一顆特殊的二叉排序樹,它比普通的多一個優先級(在本題中就是權值),使它有了堆的性質。如果沒有修改操作,我們可以根據這些性質構造一顆這樣的樹然后模擬,而本題的難度就在修改,對此可以用動規解決。
定義f[i,j,w]為第i..j的節點構成節點權值大于w的子樹遍歷的最小代價,a[i,1]保存節點的數據值,a[i,2]保存節點離散化后的權值,a[i,3]保存節點的訪問頻度,s[i,j]為第i..j的節點訪問頻度之和。
離散化權值,就是將權值按從小到大排序后用其在數組中編號來表示其權值,之所以能這樣做是因為節點權值各部相同,而每個點權值數字本身多少沒有意義,重要的是它與其它節點權值相比的大小關系,離散化后就可以將大小參差不齊的數字按大小的關系轉換為有序的編號,可以節省空間,也可動規中的一些麻煩的東西。
動規式子分兩種情況
在i..j中枚舉根節點k
若不修改,條件是k的權值>=w,則f[i,j,w]:=max(f[i,j,w],f[i,k-1,a[k,2]]+f[k+1,j,a[k,2]]+s[i,j])
若修改,則f[i,j,w]:=max(f[i,j,w],f[i,k-1,w]+f[k+1,j,w]+s[i,j]+k)
解釋:如果不修改,k必須在子樹中,其左右孩子權值均要大于k的權值;如果將k修改為根節點,其左右孩子權值可比w大很小很小的一個數字。
代碼
program treap; varf:array[0..100,0..100,0..100]of longint;a:array[1..3,0..100]of longint;s:array[0..100,0..100]of longint;n,i,m,j,w,k:longint; function min(x,y:longint):longint; beginif x<y then min:=x else min:=y; end; procedure sort(x:longint); var i,j,t:longint; beginfor i:=1 to n-1 dofor j:=i+1 to n doif a[x,i]>a[x,j] thenbegint:=a[1,i]; a[1,i]:=a[1,j]; a[1,j]:=t;t:=a[2,i]; a[2,i]:=a[2,j]; a[2,j]:=t;t:=a[3,i]; a[3,i]:=a[3,j]; a[3,j]:=t;end; end; beginassign(input,‘treap.in‘); reset(input); assign(output,‘treap.out‘); rewrite(output);readln(n,m);for i:=1 to n doread(a[1,i]); readln;for i:=1 to n doread(a[2,i]); readln;for i:=1 to n doread(a[3,i]);sort(2);for i:=1 to n doa[2,i]:=i;sort(1);for i:=1 to n dofor j:=i to n dos[i,j]:=s[i,j-1]+a[3,j];for i:=1 to n dofor j:=1 to n dofor w:=1 to n dof[i,j,w]:=maxlongint div 10;for i:=1 to n+1 dofor w:=0 to n dof[i,i-1,w]:=0;for w:=n downto 1 dofor i:=n downto 1 dofor j:=i to n dofor k:=i to j doif i=j thenif a[2,k]>=w then f[i,j,w]:=a[3,k] else f[i,j,w]:=a[3,k]+melse beginif a[2,k]>=w then f[i,j,w]:=min(f[i,j,w],f[i,k-1,a[2,k]]+f[k+1,j,a[2,k]]+s[i,j]);f[i,j,w]:=min(f[i,j,w],f[i,k-1,w]+f[k+1,j,w]+s[i,j]+m);end;writeln(f[1,n,1]);close(input); close(output); end.總結
以上是生活随笔為你收集整理的【树型DP】BZOJ1564 二叉查找树(noi2009)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在JSP页面中显示List集合·
- 下一篇: 树规总结