洛谷2607 騎士(基環樹+樹形DP)
阿新 • • 發佈:2018-11-11
傳送門
【題目分析】
第一眼:咦這不簡單樹形DP嗎?
第二眼:嗯?這不是有N條邊嗎?怎麼就樹形DP了?
第三眼:唉好像拆一條邊不就N-1條邊了嗎?哎嘿嘿我太聰明瞭。。。。
噼裡啪啦打完一交,WA完。。。。。。。一臉懵???才發現可能直接將整個圖(以為保證連通)拆成兩個聯通塊了。。。。。
然後畫畫圖,發現肯定是拆環上的邊,搞個並查集記錄一下好了。
然後對於拆掉的邊,直接分別強制兩端點不選做一遍樹形DP即可,取個較大值。考慮DP,每個點就兩個選擇:選和不選。如果不選,那麼當前點最大值就為所有兒子的最大值之和;如果選,那麼當前點最大值就為所有兒子的不選的最大值之和。
啪啪啪改完又交上去,對了三個點,一臉懵。
可能有多個聯通塊!多個!!!情況不考慮完真的難受
所以就可能要多次拆邊,要開陣列記錄。每組都要做一遍,最後答案為各組最大值之和。
【程式碼~】
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int MAXN=1e6+10; const int MAXM=2e6+10; int n,cnt; int s[MAXN],t[MAXN],tot; LL ans; int head[MAXN]; int nxt[MAXM],to[MAXM]; int a[MAXN]; LL dpfa[MAXN],dpson[MAXN]; int fa[MAXN]; int Read(){ int i=0,f=1; char c; for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar()); if(c=='-') f=-1,c=getchar(); for(;c>='0'&&c<='9';c=getchar()) i=(i<<3)+(i<<1)+c-'0'; return i*f; } int find(int x){ if(x==fa[x]) return x; return fa[x]=find(fa[x]); } void add(int x,int y){ nxt[cnt]=head[x]; head[x]=cnt; to[cnt]=y; cnt++; } void dfs(int u,int f){ dpfa[u]=a[u],dpson[u]=0; for(int i=head[u];i!=-1;i=nxt[i]){ int v=to[i]; if(v==f) continue; dfs(v,u); dpson[u]+=max(dpson[v],dpfa[v]); dpfa[u]+=dpson[v]; } } int main(){ memset(head,-1,sizeof(head)); n=Read(); for(int i=1;i<=n;++i){ fa[i]=i; } for(int i=1;i<=n;++i){ a[i]=Read(); int y=Read(); if(find(i)==find(y)){ s[++tot]=i; t[tot]=y; } else{ add(i,y),add(y,i); fa[fa[i]]=fa[y]; } } LL tt; for(int i=1;i<=tot;++i){ dfs(s[i],-1); tt=dpson[s[i]]; dfs(t[i],-1); ans+=max(tt,dpson[t[i]]); } cout<<ans; return 0; }