[ZJOI2008] 骑士

题目类型:基环树DP

传送门:>Here<

题意:给出一棵基环树,每个节点有点权。任意一条边的两端的节点不能都选,问最大和

解题思路

所谓基环树,就是只有一个简单环的树

我们熟知的树有(N)个节点(N-1)条边。再加入一条边必定形成环,且只有一个环。那么基环树就是(N)个节点(N)条边的树(严格来说不能叫树,而是仙人掌)。

因此我们如果想做树形(DP),必须删去环内的一条边。设删去边((u,v))。于是我们以(u)为根节点做一次(DP),注意此时规定不能取(v)这个点。由于没有取(v),因此需要再考虑取(v)的情况。因此以(v)为根节点再做一次(DP)

如何保证在(DP)时保证不取到对应的那个点?权值赋值为负数即可,这样选他肯定不会优,所以不会去选

Code

/*By DennyQi*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define  r  read()
#define  Max(a,b)  (((a)>(b)) ? (a) : (b))
#define  Min(a,b)  (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = 1000010;
const int MAXM = 2000010;
const int INF = 1061109567;
inline int read(){
    int x = 0; int w = 1; register int c = getchar();
    while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
    if(c == '-') w = -1, c = getchar();
    while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar(); return x * w;
}
int N,x,has_root,s,e,EE;
ll ans;
int first[MAXM],nxt[MAXM],to[MAXM],num_edge=-1;
int val[MAXN],vis[MAXN];
ll f[MAXN][2];
inline void add(int u, int v){
	to[++num_edge] = v;
	nxt[num_edge] = first[u];
	first[u] = num_edge;
}
inline void SearchRoot(int u, int father){
	int v;
	vis[u] = 1;
	for(int i = first[u]; i != -1; i = nxt[i]){
		if((v = to[i]) == father) continue;
		if(!vis[v]){
			SearchRoot(v, u);
		}
		else{
			s = u, e = v;
			EE = i;
			continue;
		}
	}
}
void DP(int u, int father){
	int v;
	f[u][0] = 0, f[u][1] = 1LL * val[u];
	for(int i = first[u]; i != -1; i = nxt[i]){
		if((v = to[i]) == father) continue;
		if(i == EE || i == (EE^1)) continue;
		DP(v, u);
		f[u][1] += f[v][0];
		f[u][0] += Max(f[v][0], f[v][1]);
	}
}
int main(){
	N = r;
	memset(first,-1,sizeof(first));
	for(int i = 1; i <= N; ++i){
		val[i] = r;
		x = r;
		add(i, x), add(x, i);
	}
	for(int i = 1; i <= N; ++i){
		if(!vis[i]){
			s = e = 0;
			SearchRoot(i, -1);
			if(!s){
				DP(i, -1);
				ans += Max(f[i][0], f[i][1]);
				continue;
			}
			
			int tmp = val[e];
			val[e] = -INF;
			DP(s, -1);
			ll res = Max(f[s][0], f[s][1]);
			val[e] = tmp;
			
			tmp = val[s];
			val[s] = -INF;
			DP(e, -1);
			val[s] = tmp;
			res = Max(res, Max(f[e][0],f[e][1]));
			ans += res;
		}
	}
	printf("%lld", ans);
	return 0;
} 
原文地址:https://www.cnblogs.com/qixingzhi/p/9504663.html