题目类型:基环树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;
}