Codeforces Round #530 (Div. 2):D. Sum in the tree (題解)
阿新 • • 發佈:2019-02-19
continue lan 代碼 裏的 解決 ron turn contest pro 為-1的結點,但這裏我們可以就把它看作一個點,然後找到非-1父親結點的s值,假設為p,那麽sv-sp就是中間結點的權值和,看作一個點的話,就是那個點的a值,同時根據這個我們可以計算出其sum值。至於這裏怎麽求sp,可以在dfs的時候記錄一下。
D. Sum in the tree
題目鏈接:https://codeforces.com/contest/1099/problem/D
題意:
給出一棵樹,以及每個點的si,這裏的si代表從i號結點到根節點的權值和。但是有些si=-1,這就相當於丟失了當前結點的數據。
假設原本每個點的權值為ai,那麽現在求sum{ai}的最小為多少,ai為非負數。
題解:
這題可以單獨看每一條鏈上的s值,假設當前結點為u,兒子結點v,那麽就有幾種情況:
1.su==-1&&sv==-1,這種不用管,繼續往下看;
2.su==-1&&sv>=0,這種情況,su以及上面可能有多個si
3.su>=0&&sv==-1,這裏就需要上面的記錄了,記錄目前的su值,方便後面找sp;
4.su>=0&&sv>=0,這裏直接往下搜索就行了。
結合上面的分析,我們只需要一個dfs記錄一下就好了,最後求au的時候就是sumu-sump,也可以在dfs的過程中處理。
但是我們剛才只是對鏈的分析,一個結點可能有多個兒子結點。想一下,會發現只有上面第2種情況會多考慮一點,因為根據哪個兒子結點來確定當前的s是一個問題。
這個問題也不難解決,取min{sv-sp}即可,一方面是讓其盡量大,另一方面是保證方案可行。
最後再判斷一下可行性就行了。
代碼如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5+5; int n; vector <int> g[N]; ll sum[N],b[N]; int flag = 0; void dfs(int u,ll a,int fa){ int son = 0; if(flag) return; int f=0; for(auto v:g[u]){ if(v==fa) continue ; if((sum[u]==-1 && sum[v]>=0) ||f){ f=1; ll now=sum[v]-a; if(sum[u]==-1) sum[u]=now+a; if(sum[u]!=-1) sum[u]=min(sum[u],now+a); } } for(auto v:g[u]){ if(v==fa) continue ; son++; if(sum[v]==-1 && sum[u]==-1){ dfs(v,a,u); continue ; } dfs(v,sum[u],u); } if(son==0&&sum[u]==-1){ b[u]=0; return ; } if(sum[u]!=-1) b[u]=sum[u]-a; } int main(){ cin>>n; for(int i=2;i<=n;i++){ int f; scanf("%d",&f); g[f].push_back(i); g[i].push_back(f); } for(int i=1;i<=n;i++) scanf("%I64d",&sum[i]); if(sum[1]==-1) sum[1]=0; dfs(1,0,-1); for(int i=1;i<=n;i++){ if(b[i]<0) flag=1; } if(flag) puts("-1"); else{ ll ans = 0; for(int i=1;i<=n;i++) ans+=b[i]; cout<<ans; } return 0; } /* 7 1 2 1 4 4 5 0 -1 3 -1 -1 3 -1 */
Codeforces Round #530 (Div. 2):D. Sum in the tree (題解)