給定一棵嚴格的treap,父親節點的優先順序必然小於兒子節點的。權值按照二叉樹的定義,左兒子小於父親小於右兒子。
深度從1開始定義,每個點除優先順序、數值之外,還有乙個訪問頻度。
訪問頻度所產生的代價是:訪問頻度*該點深度(這和事實相符)
可以用給定的k的代價,修改任意個點的優先順序為任意實數(當然,修改優先順序,樹的形態,各點深度就可能變化了)
最終的總代價為:頻度產生代價+修改代價。
最小化這個總代價。
n<=70,1<=k<=30000000
平衡樹是乙個動態的資料結構,難以抓住形態的變化,也不方便記錄深度之類。所以必須抓住不變的量當做突破口。
不管平衡樹怎麼轉,根據二叉樹的定義,它的中序遍歷一定是不變的。
所以我們可以找到這棵樹的中序遍歷,就把這棵樹變成了乙個靜態的區間,只不過每個區間所代表的點的優先順序可能會變。
發現,每乙個連續的子區間,都對應treap的連續一部分。可以把小的區間先建樹,再把大的區間用小的區間合併。我們合併的時候列舉的劃分點,就是這部分treap的樹根
區間dp順理成章。
除了f[l][r]之外,為了維護優先順序的關係,必然要再記錄一維。
發現,只要根節點的優先順序確定,子樹的優先順序的範圍就確定了。
所以考慮記錄根節點優先順序。(這裡優先順序只考慮相對大小,而且範圍又大,所以要離散化為1~n)
但是,樸素的f[l][r][w]中,w單單記錄根節點優先順序的話,由於子樹所有大於w的都可以轉移,還要for一遍。狀態n^3,轉移n^2,會爆。
所以,我們令f[l][r][w]表示,將l~r這段區間建成treap,其中根節點優先順序大於等於w的最小代價。
根據列舉的根節點是否修改,可以設計轉移方程是:
修改:f[l][r][w]=min(f[l][r][w],f[l][k-1][w]+f[k+1][r][w]+k+sum[r]-sum[l-1]) ————其中,sum[i]表示,區間中,1~i的訪問頻度和
當劃分點的優先順序ch[k]大於w時,可以不修改。
f[l][r][w]=min(f[l][r][w],f[l][k-1][ch[k]]+f[k+1][r][ch[k]]+sum[r]-suim[l-1])
最後答案就是:f[1][n][1];
注意,o迴圈的時候,必須倒序!!因為ch[k]>=o時候,要從o更大的地方獲取最小值,必須先把o較大的處理完。
#includeusingnamespace
std;
typedef
long
long
ll;const
int n=77
;const ll inf=2e18;
ll f[n][n][n];
intn;
ll m;
inta[n];
inttot;
intw[n],p[n],d[n];
intprio[n];
ll sum[n];
int ch[n];//
離散化後的優先順序
bool cmp(int a,int
b)int
main()
//l=1的初值
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+d[a[i]];//
字首和
for(int l=2;l<=n;l++)
for(int i=1;i<=n;i++)
}else
else
if(k==j)//
同理
else}}
}printf(
"%lld
",f[1][n][1
]);
return0;
}
太噁心了。為了保證l<=r,做出了巨大的討論。
其實不用這麼麻煩,只要讓l>r的時候,賦值為0就好,相當於不存在。根本不影響答案。
#includeusingnamespace
std;
typedef
long
long
ll;const
int n=77
;const ll inf=2e18;
ll f[n][n][n];
intn;
ll m;
inta[n];
inttot;
intw[n],p[n],d[n];
intprio[n];
ll sum[n];
int ch[n];//
離散化後的優先順序
bool cmp(int a,int
b)int
main()
//不放心,可以考慮代入長度小於等於2的情況。0的作用就出來了。
//連初始化l=1都省了。
printf("
%lld
",f[1][n][1
]);
return0;
}
總結:1.對於琢磨不透的變化,一定有不變的東西。一定要抓住其中的不變數,作為突破口。
2.迴圈順序要注意,乙個是不能有後效性,乙個是要保證能影響到這個狀態的所有狀態都處理完了。
3.注意考慮清楚所有可能轉移的方式。
NOI2009 二叉查詢樹
戳我 我剛看到這道題時無從下手,連 dp 狀態都不知道怎麼設。於是墜入題解的深淵 根據定義,該二叉查詢樹中每個結點的資料值都比它左兒子結點的資料值大,而比它右兒子結點的資料值小。則因資料值不會被修改,所以樹的中序遍歷不變 先左再中後右 於是我們可以在樹的中序遍歷上進行區間 dp 乙個區間就能代表一顆...
NOI2009 二叉查詢樹
給出乙個 n 個節點的二叉排序樹的原始資料值 d i 權值 v i 和訪問頻度 s i 你可以根據需要把結點的權值改為任何實數,但每次修改你會付出 k 的額外修改代價,且修改後所有結點的權值必須仍保持互不相同。求整棵樹的訪問代價與額外修改代價的最小和。n le 70,1 le k le 3 10 7...
bzoj1564 NOI2009 二叉查詢樹
首先先說明乙個坑點,這裡說數不能重複,但是數又可以取全體實數,而且修改代價又和數沒有關係,那麼我們其實可以直接看成整數的。然後我們是知道中序遍歷的 所以我們可以區間dp一下,設f i j k 表示i j建成一棵子樹,根的大小大於 否則值不變的時候只會影響1個點,答案沒有單調性求值複雜,還要多乙個n的...