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; }