1. 程式人生 > 實用技巧 >2020杭電多校(二) In Search of Gold(二分+dp)

2020杭電多校(二) In Search of Gold(二分+dp)

題目滿足單調性,考慮先二分後進行check

對於check,用樹形dp來表示狀態是否可達,設計d[i][j]表示以j為根節點的子樹,使用了i個a邊,能滿足長度不超過二分答案值的離i最遠距離的最小值

含義就是,對於每種合法方案,都儲存最小的距離,這樣對之後的狀態轉移的最優的。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pll;
const int N=4e5+10;
const
int mod=1e9+7; const ll inf=1e18; int h[N],ne[N],e[N],w1[N],w2[N],idx; int n,k,sz[N]; ll f[25][200020]; ll ans[N]; void add(int a,int b,int x,int y){ e[idx]=b,ne[idx]=h[a],w1[idx]=x,w2[idx]=y,h[a]=idx++; } void dfs(int u,int fa,ll up){ sz[u]=1; int i; for(i=0;i<=20;i++) ans[i]=inf; f[
0][u]=0; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa) continue; dfs(j,u,up); int op=min(k,sz[u]+sz[j]); for(int x=0;x<=op;x++) ans[x]=inf; for(int x=0;x<=min(k,sz[u]);x++){ for(int y=0;y<=min(k,sz[j]);y++){
if(x+y<=op&&f[x][u]+f[y][j]+w2[i]<=up){ ans[x+y]=min(ans[x+y],max(f[x][u],f[y][j]+w2[i])); } if(x+y+1<=op&&f[x][u]+f[y][j]+w1[i]<=up){ ans[x+y+1]=min(ans[x+y+1],max(f[x][u],f[y][j]+w1[i])); } } } sz[u]+=sz[j]; for(int x=0;x<=op;x++) f[x][u]=ans[x]; } } bool check(ll mid){ int i,j; for(i=0;i<=k;i++){ for(j=1;j<=n;j++) f[i][j]=inf; } dfs(1,-1,mid); return (f[k][1]<inf); } int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ cin>>n>>k; int i; for(i=1;i<=n;i++) h[i]=-1; ll l=1,r=0; for(i=1;i<n;i++){ int a,b,c,d; cin>>a>>b>>c>>d; add(a,b,c,d); add(b,a,c,d); r+=max(c,d); } while(l<r){ ll mid=l+r>>1; if(check(mid)) r=mid; else l=mid+1; } cout<<l<<endl; idx=0; } return 0; }
View Code