1. 程式人生 > 實用技巧 >HDU多校2020 第八場 1012/6866--Linuber File System(樹上DP

HDU多校2020 第八場 1012/6866--Linuber File System(樹上DP

題意:http://acm.hdu.edu.cn/showproblem.php?pid=6866

每個節點都有值域區間,一開始每個點值都為0,你每次可以選一個子樹都+x,-x,0(任意),問最終所有節點滿足值域的最小操作次數。

思路:

dp開二維,第二維計個值域區間,n方瞎搞搞就行,場上明顯榜被帶歪了,簽到題水平(狗頭)

程式碼有改動,可能不AC

int a[N],b[N],vl[N],vr[N];
int LS(int n)
{
    int m=0;
    for(int i=1;i<=n;++i)
        b[++m]=a[i];
    sort(b+1,b+1+m);
    m
=unique(b+1,b+1+m)-b-1; for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+m,a[i])-b; return m; } int top; int dp[2010][8010]; void dfs(int u,int f) { for(int i=1;i<=top;++i)dp[u][i]=0; for(int i=head[u];i;i=edge[i].next) { int to=edge[i].to; if(to==f)continue
; dfs(to,u); for(int j=1;j<=top;++j)dp[u][j]+=dp[to][j]; } int L=vl[u]*2,R=vr[u]*2; if(L>R)swap(L,R); int min_=INF; for(int i=L;i<=R;++i)min_=min(min_,dp[u][i]); for(int i=1;i<=top;++i) { if(i<L||i>R) { dp[u][i]
=1+min_; } else { if(dp[u][i]!=min_) dp[u][i]=1+min_; } } } void solve() { int n; cin>>n; Init(n); for(int i=1;i<n;++i) { int u,v; cin>>u>>v; add(u,v); add(v,u); } for(int i=1;i<=n+n;++i)cin>>a[i]; a[n+n+1]=0; top=LS(n+n+1); for(int i=1,j=1;i<=n+n;i+=2,++j) vl[j]=a[i],vr[j]=a[i+1]; top=top*2+1; dfs(1,0); int ans=dp[1][a[n+n+1]*2]; cout<<ans<<endl; }