【牛客 - 303K第十五届浙江大学宁波理工学院程序设计大赛(同步赛)】Technology Tree(树形dp,tricks)
題干:
?
在星際爭霸(StarCraft)中,有3個種族。對于任意一個種族,他們的建筑建造都是有一個順序的。這個順序正好是一個樹形結構,我們稱之為"科技樹"(Technology tree)。
在科技樹中,只有一個建筑是不需要前置建筑的,我們把這個建筑的編號設為1。其他的建筑,有且僅有一個前置建筑。
比如建筑2的前置建筑為建筑1,意思是只有先建造了建筑1,才能建造建筑2。
一個種族有n個建筑,建筑1沒有前置建筑,建筑i(2≤i≤n)的前置建筑為f。每個建筑的建造都需要費用,建筑i(1≤i≤n)的建造花費為a晶體礦和b高能瓦斯。
現在tokitsukaze想知道,如果想要建造建筑x,總共需要消耗多少晶體礦和高能瓦斯。
輸入描述:
第一行包含一個T(T≤10),表示T組數據。對于每組數據: 第一行包含兩個正整數n,q(1≤n,q≤20000),表示有n個建筑和q次查詢。 接下來n行,每行包含兩個整數a,b(0≤a,b≤300),表示建造建筑i需要花費a晶體礦和b高能瓦斯。 接下來一行,包含n-1個正整數f(1≤f≤n)。第i個(1≤i<n)正整數fi(1≤fi<i)表示建筑i+1的前置建筑為fi。 接下來q行,每行包含一個正整數x,表示詢問。輸出描述:
對于每個詢問,輸出一行,包含兩個整數c,d(用空格隔開),表示如果想要建造建筑x,總共需要消耗c晶體礦和d高能瓦斯。?
示例1
輸入
復制
1 4 4 1 5 10 100 200 50 66 88 1 1 2 1 2 3 4輸出
復制
1 5 11 105 201 55 77 193說明
第一組樣例:如果想要建造建筑1,總共需要消耗1晶體礦和5高能瓦斯。如果想要建造建筑2,需要先建造建筑1,總共需要消耗1+10晶體礦和5+100高能瓦斯。 如果想要建造建筑3,需要先建造建筑1,總共需要消耗1+200晶體礦和5+50高能瓦斯。 如果想要建造建筑4,需要先建造建筑1和建筑2,總共需要消耗1+10+66晶體礦和5+100+88高能瓦斯。解題報告:
? ?就是記憶化一個樹形dp就行了唄,,不算難想。但是因為輸入的巧妙,這題可以用巧妙的解法,詳見下面Qls的思路。OrzOrz
?
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair #define fi first #define se second using namespace std; const int MAX = 2e4 + 5; struct Node {int j,g; } node[MAX]; int pre[MAX]; ll dpg[MAX],dpj[MAX]; ll dfsg(int cur,int root) {if(cur == 1) return dpg[1] = node[1].g ;if(dpg[cur] != -1) return dpg[cur];dpg[cur]=0;dpg[cur] += dfsg(pre[cur],cur);dpg[cur] += node[cur].g;return dpg[cur]; } ll dfsj(int cur,int root) {if(cur == 1) return dpj[1] = node[1].j ;if(dpj[cur] != -1) return dpj[cur];dpj[cur]=0;dpj[cur] += dfsj(pre[cur],cur);dpj[cur] += node[cur].j;return dpj[cur]; } int main() {int t,a,b,q,n;cin>>t;while(t--) {memset(dpj,-1,sizeof dpj);memset(dpg,-1,sizeof dpg); //chushihuascanf("%d%d",&n,&q);for(int i = 1; i<=n; i++) {scanf("%d%d",&node[i].j,&node[i].g);}for(int i = 2,x; i<=n; i++) {scanf("%d",&x);pre[i]=x;}for(int i = 1; i<=n; i++) {dfsg(i,-1);dfsj(i,-1);}int x;while(q--) {scanf("%d",&x);printf("%lld %lld\n",dpj[x],dpg[x]);}}return 0 ;}其實這個代碼完全可以返回一個結構體或者用pair或者用兩個引用,,但是這里因為懶惰,,沒有改代碼,(因為第一次寫的時候不知道要求輸出 晶體礦和高能瓦斯 分開輸出。所以就寫了一個dp,,然后發現輸出格式后又懶得改然后就直接復制一波,改改變量就交了、)
Qls思路:(因為這題是按照順序讀入的:fi(1≤fi<i)? ?所以可以這么寫,,也算是個小技巧吧,,,不這么讀入的話,就不能這么狀態轉移了,,所以還是老老實實寫樹上的吧)
#include<bits/stdc++.h> using namespace std; const int MAXN=20005; int a[MAXN],b[MAXN]; int main() {int T;scanf("%d",&T);while(T--){int n,q;scanf("%d%d",&n,&q);for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]);for(int i=2;i<=n;i++){int f;scanf("%d",&f);a[i]+=a[f],b[i]+=b[f];}for(int i=1;i<=q;i++){int x;scanf("%d",&x);printf("%d %d\n",a[x],b[x]);}}return 0; }ps:神仙就是神仙,,,一小時秒了九個題,,強勢Rank1、、OrzOrz
總結
以上是生活随笔為你收集整理的【牛客 - 303K第十五届浙江大学宁波理工学院程序设计大赛(同步赛)】Technology Tree(树形dp,tricks)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 申请信用卡身份证有效期怎么填写 身份证过
- 下一篇: 申请信用卡软件哪个好 2017信用卡软件