[bzoj] 1040: [ZJOI2008]骑士 发表于 Jan 1 2015 | 分类于 bzoj | 题意 传送门 分析环套树的一般做法是,枚举每条环上的边,将其删去后做树形dp 代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899#include <cstdio>int CH , NEG ;template<typename T>inline void read(T& ret) { ret = NEG = 0 ; while (CH=getchar() , CH<'!') ; if (CH == '-') NEG = true , CH = getchar() ; while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ; if (NEG) ret = -ret ;}#include <cstring>#define maxn 1000010LL#define maxm 1000010LL#define max(x,y) ((x)>(y)?(x):(y))typedef long long ll ;struct FST { int to , next ; } e[maxm<<1] ;int star[maxn] = {0} , tote = 1 ;void AddEdge(int u , int v) {truee[++tote].to = v ; e[tote].next = star[u] ; star[u] = tote ;}ll val[maxn] = {0} ;bool done[maxn] = {0} ;bool vis[maxn] = {0} ;ll f[maxn][2] = {0} ;int rt1 , rt2 ;void GetCycle(int u , int edg) {/* dfs找到环上的两点,并将这棵环套树中的节点标记为访问过 */int v , p ;truedone[u] = true ;truefor (p = star[u] ; p ; p = e[p].next) {truetruev = e[p].to ;truetrueif (p == (edg^1)) continue ;truetrueif (done[v]) { if (!rt1) rt1 = u , rt2 = v ; }truetrueelse GetCycle(v , p) ;true}}void dp(int u) {int v , p ;truevis[u] = true ;truef[u][0] = 0 , f[u][1] = val[u] ;truefor (p = star[u] ; p ; p = e[p].next) {truetruev = e[p].to ;truetrueif (!vis[v]) {truetruetruedp(v) ;truetruetruef[u][0] += max(f[v][0] , f[v][1]) ;truetruetruef[u][1] += f[v][0] ;truetrue}true}}int n ;ll tmp , ans = 0 ;int main() {int u , v ;// #define READtrue#ifdef READtruetruefreopen(".in" ,"r",stdin ) ;truetruefreopen(".out","w",stdout) ;true#endiftrueread(n) ;truefor (u = 1 ; u <= n ; u ++ ) {truetrueread(val[u]) , read(v) ;truetrueAddEdge(u , v) ;truetrueAddEdge(v , u) ;true}truefor (u = 1 ; u <= n ; u ++ ) {truetrueif (!done[u]) {truetruetruert1 = rt2 = 0 ;truetruetrueGetCycle(u , 0) ;truetruetrueif (rt1 != 0) {truetruetruetruememset(vis , false , sizeof vis) ;truetruetruetruedp(rt1) ;truetruetruetruetmp = f[rt1][0] ;truetruetruetruememset(vis , false , sizeof vis) ;truetruetruetruedp(rt2) ;truetruetruetrueans += max(tmp , f[rt2][0]) ;truetruetrue} else {truetruetruetruememset(vis , false , sizeof vis) ;truetruetruetruedp(u) ; ans += max(f[u][1] , f[u][0]) ;truetruetrue}truetrue}true}trueprintf("%lld\n", ans) ;true#ifdef READtruetruefclose(stdin) ; fclose(stdout) ;true#elsetruetruegetchar() ; getchar() ;true#endiftruereturn 0 ;}