hdu6866 Linuber File System 2020杭电多校第八场

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

 

你可能感兴趣的:(树形DP)