• BZOJ1040 [ZJOI2008]骑士


    题意:基环树最大独立集


    思路:

    像这样的题就是朴素的树形dp很easy的,我们用一些技巧转化为变体树。

    直接套用仙人掌的动态规划做法:(基环树其实也属于一种仙人掌)

    首先利用tarjan算法,假设遇到自己与儿子之间的边为割边则依照树边处理。

    Tarjan后看一下与自己相连的边,假设某个相邻点不是自己的儿子,而且入栈序比自己大,那么说明自己是环上的的最高点,此时我们对环上特别的进行dp,在这之后将环上全部点的决策值转移到环上的最高点上,那么能够觉得这个环连带着环下的子树都被缩成这一个点了。于是向上返回就可以。

    终于我们仅仅须要输出一開始进行tarjan那个点的最优值就可以。


    Code:

    #include <cstdio>
    #include <cstring>
    #include <cctype>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    typedef long long LL;
    
    #define N 1000010
    
    int head[N], next[N << 1], end[N << 1];
    void addedge(int a, int b) {
    	static int q = 1;
    	end[q] = b;
    	next[q] = head[a];
    	head[a] = q++;
    }
    
    int w[N];
    
    LL dp[N][2];
    
    int dfn[N], low[N], pa[N], tclock;
    
    int sav[N], size;
    LL work[N][2];
    void Dp(int top, int bottom) {
    	int tmp = bottom;
    	size = 0;
    	for(; tmp != top; tmp = pa[tmp])
    		sav[++size] = tmp;
    	sav[++size] = top;
    	
    	register int i;
    	work[1][0] = dp[sav[1]][0], work[1][1] = dp[sav[1]][1];
    	for(i = 2; i <= size; ++i) {
    		work[i][0] = max(work[i - 1][0], work[i - 1][1]) + dp[sav[i]][0];
    		work[i][1] = work[i - 1][0] + dp[sav[i]][1];
    	}
    	dp[top][0] = work[size][0];
    	
    	work[1][0] = dp[sav[1]][0], work[1][1] = -1LL << 60;
    	for(i = 2; i <= size; ++i) {
    		work[i][0] = max(work[i - 1][0], work[i - 1][1]) + dp[sav[i]][0];
    		work[i][1] = work[i - 1][0] + dp[sav[i]][1];
    	}
    	dp[top][1] = work[size][1];
    }
    
    void dfs(int x) {
    	dfn[x] = low[x] = ++tclock;
    	dp[x][1] = w[x];
    	for(int j = head[x]; j; j = next[j]) {
    		if (!dfn[end[j]]) {
    			pa[end[j]] = x;
    			dfs(end[j]);
    			if (low[end[j]] > dfn[x]) {
    				dp[x][1] += dp[end[j]][0];
    				dp[x][0] += dp[end[j]][0] > dp[end[j]][1] ? dp[end[j]][0] : dp[end[j]][1];
    			}
    			low[x] = min(low[x], low[end[j]]);
    		}
    		else if (end[j] != pa[x])
    			low[x] = min(low[x], dfn[end[j]]);
    	}
    	for(int j = head[x]; j; j = next[j])
    		if (pa[end[j]] != x && dfn[x] < dfn[end[j]])
    			Dp(x, end[j]);
    }
    int main() {
    	#ifndef ONLINE_JUDGE
    	freopen("tt.in", "r", stdin);
    	#endif
    	
    	int n;
    	scanf("%d", &n);
    	
    	register int i, j;
    	int x;
    	for(i = 1; i <= n; ++i) {
    		scanf("%d%d", &w[i], &x);
    		addedge(i, x);
    		addedge(x, i);
    	}
    	
    	LL tot = 0;
    	for(i = 1; i <= n; ++i) {
    		if (!dfn[i]) {
    			dfs(i);
    			tot += dp[i][0] > dp[i][1] ? dp[i][0] : dp[i][1];
    		}
    	}
    	
    	printf("%lld", tot);
    	
    	return 0;
    }

  • 相关阅读:
    小甲鱼系列→第一章.基础知识
    FusionCharts-堆栈图、xml格式、刷新数据、添加事件link、传参
    FireBug提示:本页面不包含 JavaScript,明明是包含js的。
    Angular-Chart.js 初接触;;;
    错误 Metadata file 'C:CommoninDebugCommon.dll' could not be found
    UML--PowerDesigner使用小结
    java8入门 错误:找不到或者无法加载主类
    “基础提供程序在Open上失败”
    设计模式--目录开篇
    020医疗项目-模块二:药品目录的导入导出-介绍药品表
  • 原文地址:https://www.cnblogs.com/llguanli/p/7205699.html
Copyright © 2020-2023  润新知