http://acm.hdu.edu.cn/showproblem.php?pid=6866
又从wcy聚聚那学到了QAQ
这题比赛的时候猜想一定是选l[i]或者r[i],然而存在加法问题,就完全不知道怎么办
然而可以转化一下,设dp[u][i]为u的子树,从1到u的路径上所有点的加的值是i时,这棵子树中最小的修改值的次数
枚举u的一个儿子v中所有的可能值dp[v][j], 如果j=i,也就是说从u到v时不需要修改v的值,否则需要修改也就是+1,那么dp[u][i]+=v的最小值就行了。
我们发现i和j的值是可以离散化的,我们把所有的l[i]-1和r[i]加入进去,l[i]-1也就是说严格小于l[i],离散化以后由于此题是随便加值,所以并不会改变dp最后的答案。如果不离散化需要对所有子节点的区间进行排序会多一个log
#include<bits/stdc++.h>
using namespace std;
const int maxl=4e3+10;
int n,m,cnt,ans;
int l[maxl],r[maxl],b[maxl],tmp[maxl];
int dp[maxl][maxl],mi[maxl];
vector<int> e[maxl];
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
e[i].clear();
int u,v;
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
cnt=0;b[++cnt]=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&l[i],&r[i]);
b[++cnt]=l[i]-1;b[++cnt]=r[i];
}
sort(b+1,b+1+cnt);
cnt=unique(b+1,b+1+cnt)-b-1;
for(int i=1;i<=n;i++)
{
l[i]=lower_bound(b+1,b+1+cnt,l[i])-b;
r[i]=lower_bound(b+1,b+1+cnt,r[i])-b;
}
}
inline void dfs(int u,int fa)
{
mi[u]=n+1;
for(int i=1;i<=cnt;i++)
dp[u][i]=n+1;
int sum=0;
for(int v:e[u])
if(v!=fa)
{
dfs(v,u);
sum+=mi[v]+1;
}
for(int i=l[u];i<=r[u];i++)
{
dp[u][i]=sum;
for(int v:e[u])
if(v!=fa)
{
if(dp[v][i]==mi[v])
dp[u][i]--;
}
mi[u]=min(mi[u],dp[u][i]);
}
}
inline void mainwork()
{
dfs(1,0);
ans=mi[1];int id=lower_bound(b+1,b+1+cnt,0)-b;
if(dp[1][id]!=mi[1])
ans++;
}
inline void print()
{
printf("%d\n",ans);
}
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}