樹上貪心 E. Tree Shuffling 暑訓第一天
阿新 • • 發佈:2020-07-03
樹上貪心 E. Tree Shuffling
題目大意:
給你一棵樹,這棵樹每一個點有三個值,分別是a,b,c,a表示這個點的權值,b表示這個點本來的值,c表示這個點想要變成的值(b和c都是0或者1),對於一棵子樹u,你可以選擇k個節點,然後這k個節點進行重新洗牌,花費是k*a[u],問是否可以通過重新洗牌使得所有的節點都變成想要的節點,是則輸出最小的花費,不是輸出-1。
題解:
這個題目其實不是特別難,但是有點繞,一開始又想錯了一部分,所以最後做的都想睡覺了。。。
這個維護一條鏈上的最小值,如果這個值是從根節點到現在位置的最小值,則更新所有可以更新的節點,如果不是則可知最小值在其祖先節點,從根節點開始維護最小值,從葉子節點開始更新。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; typedef long long ll; const int maxn = 2e5+10; ll a[maxn],b[maxn],c[maxn],ans; vector<int>G[maxn]; void add(int u,int v){ G[u].push_back(v); G[v].push_back(u); } void dfs1(int u,int pre,ll mins){ mins=min(mins,a[u]); for(int i=0;i<G[u].size();i++){ int v=G[u][i]; if(v==pre) continue; dfs1(v,u,mins); b[u]+=b[v]; c[u]+=c[v]; } if(a[u]==mins){ // printf("b=%lld c=%lld\n",b[u],c[u]); ll num = min(b[u],c[u]); ans+=num*2*a[u]; b[u]-=num; c[u]-=num; // printf("u=%d pre=%d mins=%lld num=%lld ans=%lld b=%lld c=%lld\n",u,pre,mins,num,ans,b[u],c[u]); } } int main(){ int n; int f1=0,f2=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lld%lld%lld",&a[i],&b[i],&c[i]); if(b[i]==c[i]) b[i]=c[i]=0; f1+=b[i],f2+=c[i]; } if(f1!=f2){ printf("-1\n"); return 0; } for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); } ans=0; dfs1(1,0,inf64); printf("%lld\n",ans); return 0; } /* 8 82 0 0 3 1 1 53 0 0 5 0 0 81 0 1 56 1 0 99 1 0 87 0 1 5 7 2 8 4 7 4 1 3 2 2 5 8 6 ---- 7 6 0 0 2 0 1 4 0 1 10 1 0 6 1 0 3 0 0 9 1 1 6 3 5 6 2 6 6 4 5 7 1 7 */