1. 程式人生 > >Codeforces Round #530 (Div. 2) D. Sum in the tree 樹上貪心

Codeforces Round #530 (Div. 2) D. Sum in the tree 樹上貪心

關系 pac 題意 rst ret next 最大 memset add

D. Sum in the tree

題意

給出一顆樹,奇數層數的點有值,值代表從1到該點的簡單路的權值的和,偶數層數的點權值被擦去了 問所有節點的和的最小可能是多少

思路

對於每一個-1(也就是值未知的點)其所填的值的最小值小於等於他的自己點中已知的點的權值 換個說法就是 一個-1點有多個子樹 那麽這個點的值最小也是這幾個子樹裏面的最大的值,才能使得其合法 從根節點遞歸求值即可
其中註意 這裏計算權值和的時候,因為已知每個點到根節點的路徑的點的權值和所以計算一個節點以及其子樹到根節點的權值和的,等於這個節點的每個子節點的樹到根節點的權值和的和減去這一個點可以取得的最小值*(支路數-1) 也就相當於一個容斥關系

ps:當時我是怎麽寫出那麽毒瘤的代碼的。。。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5+5;
typedef long long ll;
#define F first
#define S second
#define pb push_back
#define pii pair<int ,int >
#define mkp make_pair
#define int long long 
const int inf=0x3f3f3f3f;
int head[maxn];
int s[maxn];
int size=0;
struct Node{
    int to,next;
}edge[maxn];
void add(int x,int y){
    edge[size].to=y;
    edge[size].next=head[x];
    head[x]=size++;
}
int ans=0;
int ok=1;
pair<int,int>  dfs(int x,int fa,int nowmax){
    int sum=0;
    int cnt=0;
    int minnum=0x3f3f3f3f;
    for(int i=head[x];i!=-1;i=edge[i].next){
        int y=edge[i].to;
        if(fa!=y){
            cnt++;
            if(nowmax>s[y]&&s[y]!=-1){
                printf("-1\n");
                ok=0;
                return mkp(-1,-1);
            }
             pii tmp=dfs(y,x,max(nowmax,s[y]));
             sum+=tmp.F;
             minnum=min(minnum,tmp.S);
        }
    }
//  cout<<x<<" "<<sum<<" "<<nowmax<<" "<<minnum<<endl;
    if(cnt==0)return mkp(nowmax,nowmax);
    return mkp(sum-(cnt-1)*minnum,nowmax);
}
int32_t main(){
    int n;
    scanf("%lld",&n);
    int tmp;
    memset(head,-1,sizeof(head));
    size=0;
    for(int i=2;i<=n;i++){
        scanf("%lld",&tmp);
        add(tmp,i);
    }
    for(int i=1;i<=n;i++){
        scanf("%lld",&s[i]);
    }
    int num=dfs(1,-233,s[1]).F;
    if(ok)cout<<num<<endl;


    return 0;
}

Codeforces Round #530 (Div. 2) D. Sum in the tree 樹上貪心