zoukankan      html  css  js  c++  java
  • CF337D Book of Evil 换根树形DP

    稍微复杂的换根 DP,我能一发 A 掉的还是不多的...

    题目大意

    给出一棵有 (n) 个结点的树,其中 (m) 个结点 (p_1,p_2,cdots,p_m) 作特殊标记,令 (dis(x,y)) 代表结点 (x)(y) 简单路径上边数,求有多少个点 (x) ,满足 (forall i in [1,m] ,max{dis(x,p_i)} le d)


    题解

    不妨令 (1) 为根。

    考虑结点 (x) 的最远标记点,可以在 (x) 的子树 (T(x)) 内,也可以在 (x) 的子树外。

    对这两种情况分别讨论。

    ( exttt{Part I})

    (x) 的子树内情况比较简单,可以通过一次 dfs 求出。

    (dp(x))(T(x)) 内最远标记点到 (x) 的距离,如果 (T(x)) 内没有标记点,则 (dp(x) = +infty)

    但在这个 dfs 过程中,还要维护(T(x)) 内第二远标记点到 (x) 的距离 (dp2(x)),原因将在 ( exttt{Part II}) 解释。

    ( exttt{Part II})

    (x) 的子树外情况比较复杂,但可以自然地想到是一个换根 DP:根 (1) 号点不存在子树外情况,已经可以求解。

    假设 (y)(x) 的任一儿子,此时对 (y) 有两种情况:

    • (dp(x) = dp(y) + 1) ,即 (dp(x))(dp(y)) 转移而来
    • (dp(x) eq dp(y) + 1) ,即 (dp(x)) 不是由 (dp(y)) 转移而来。

    以题目样例为例

    其中 (1) 号点只有一个儿子 (5) 号点,那么 (5) 号点符合上述的第一种情况,也就是说,(1) 号点的最远点就在孩子 (5) 号子树内。

    此时,如果从 (1) 号点向 (5) 号点换根,如果使用 (dp(1)),则 (5) 号点子树外的情况并未得到考虑,所以还需要记录 ( exttt{Part I}) 中所述的 (dp2(x)) ,并在换根过程中分类讨论。

    其他细节请见代码。


    ( exttt{Code})

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    
    template < typename Tp >
    void read(Tp &x) {
    	x = 0; int fh = 1; char ch = 1;
    	while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    	if(ch == '-') fh = -1, ch = getchar();
    	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    	x *= fh;
    }
    
    const int maxn = 100000 + 7;
    const int maxm = 200000 + 7;
    const int INF = 0x3f3f3f3f;
    
    int n, m, d, dp[maxn], dp2[maxn];
    bool mark[maxn];
    
    int Head[maxn], Next[maxm], to[maxm], tot;
    void addedge(int x, int y) {
    	to[++tot] = y, Next[tot] = Head[x], Head[x] = tot;
    }
    void add(int x, int y){
    	addedge(x, y); addedge(y, x);
    }
    
    void Init(void) {
    	read(n); read(m); read(d);
    	for(int i = 1, x; i <= m; i++) {
    		read(x); mark[x] = true;
    	}
    	for(int i = 1, x, y; i < n; i++) {
    		read(x); read(y);
    		add(x, y);
    	}
    }
    
    void dfs(int x, int fa) {
    	dp[x] = dp2[x] = INF;
    	for(int i = Head[x] ;i ; i = Next[i]) {
    		int y = to[i];
    		if(y == fa) continue;
    		dfs(y, x);
    		if(dp[y] != INF) {
    			if(dp[x] == INF) dp[x] = dp[y] + 1;
    			else {
    				if(dp[y] + 1 > dp[x]) {
    					dp2[x] = dp[x];
    					dp[x] = dp[y] + 1;
    				}
    				else if(dp2[x] == INF) dp2[x] = dp[y] + 1;
    				else dp2[x] = max(dp2[x], dp[y] + 1);
    			}
    		}
    	}
    	if(dp[x] == INF) if(mark[x]) dp[x] = 0;
    }
    
    int ans;
    
    void dfs2(int x, int fa, int mov) {
    	if(mov == INF && mark[fa]) mov = 1;
    //	printf("id = %d, fa = %d, mov = %d, dp[x] = %d
    ", x, fa, mov, dp[x]);
    	if((dp[x] <= d || dp[x] == INF) && (mov <= d || mov == INF)) {
    		++ans;
    	}
    	for(int i = Head[x]; i; i = Next[i]) {
    		int y = to[i];
    		if(y == fa) continue;
    		if(dp[x] == dp[y] + 1) {
    			if(mov == INF && dp2[x] != INF) dfs2(y, x, dp2[x] + 1);
    			else if(mov != INF && dp2[x] == INF) dfs2(y, x, mov + 1);
    			else if(mov == INF && dp2[x] == INF) dfs2(y, x, INF);
    			else dfs2(y, x, max(dp2[x], mov) + 1);
    		}
    		else {
    			if(mov == INF && dp[x] != INF) dfs2(y, x, dp[x] + 1);
    			else if(mov != INF && dp[x] == INF) dfs2(y, x, mov + 1);
    			else if(mov == INF && dp[x] == INF) dfs2(y, x, INF);
    			else dfs2(y, x, max(dp[x], mov) + 1);
    		}
    	}
    }
    
    void Work(void) {
    	dfs(1, 0);
    //	for(int i = 1; i <= n; i++) {
    //		printf("%d : %d
    ", i, dp[i]);
    //	}
    	dfs2(1, 0, INF);
    	printf("%d
    ", ans);
    }
    
    int main(void) {
    	Init();
    	Work();
    	return 0;
    }
    
  • 相关阅读:
    F2etest v2.0.0 正式发布 ,阿里巴巴开源测试方案
    Spring-Wind 1.1.1 发布,SSM 架构核心库
    通过nginx配置文件抵御攻击 | WooYun知识库
    阿里云X-Forwarded-For 发现tomcat记录的日志全部来自于SLB转发的IP地址,不能获取到请求的真实IP。
    openresty+lua在反向代理服务中的玩法 | WooYun知识库
    java~lambda表达式让查询更优雅
    java~日期与字符串的转化
    java~google样式检查和命名规范
    springboot~Mongodb的集成与使用
    springboot~JPA把ORM统一起来
  • 原文地址:https://www.cnblogs.com/liubainian/p/13551519.html
Copyright © 2011-2022 走看看