bzoj1040: [ZJOI2008]骑士

题目链接

bzoj1040: [ZJOI2008]骑士

题解

讨厌关系出度为0,可能有环,并且每个联通块内只有一个环 没有自环
构成基环树森林
选取骑士不能去相邻的
考虑将一个联通块中的环断开,这样就构成一棵树,对于断开的边相连的点分别不取,进行dp
答案就是每个联通块的贡献和

代码

#include<cstdio>
#include<cstring>
#include<algorithm>

#define int long long
const int maxn = 1000007;
inline int read () {
    int x = 0,f = 1;
    char c = getchar ();
    while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
    while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar();
    return x*f;
}
struct node{
    int v,next;
}edge[maxn << 1];
int head[maxn],num = 1;
bool vis[maxn];
inline void Add_edge(int u,int v) { edge[++ num].v = v,edge[num].next = head[u];head[u] = num; }
int son [maxn] ,Val [maxn]; 
int n,father[maxn],R1,R2,Flag,val; 
void Find_Link(int x,int fa) {
    vis[x] = 1;
    for(int i = head[x];i;i = edge[i].next) {
        int v = edge[i].v;
        if(v == fa) continue;
        if(vis[v]) {
            R1 = x;R2 = v;Flag = i;
        }
        else Find_Link(v,x);
    }
}
int dp[maxn][2];
void  dfs(int x,int fa) {
    dp[x][1] += Val[x];
    for(int i = head[x];i;i = edge[i].next) {
        int v = edge[i].v;
        if(v == fa || i == Flag || (i^1) == Flag) continue;
        dfs(v,x);
        dp[x][1] += dp[v][0];
        dp[x][0] += std::max(dp[v][1],dp[v][0]);
    }
}
main () {
    n = read();
    for(int a,i = 1;i <= n;++ i) {
        Val[i] = read();
        Add_edge(a = read(),i);
        Add_edge(i,a);
    }
    int ans = 0 ;
    for(int tmp,i = 1;i <= n;++ i) {
        if(!vis[i]) {
            R1 = R2 = 0;
            Find_Link(i,i);
            if(R1 == R2) { 
                dfs(i,i);
                ans += std::max(dp[i][0],dp[i][1]);
                continue;
            }
            dfs(R1,R1);tmp = dp[R1][0];
            memset(dp,0,sizeof dp);
            dfs(R2,R2);ans += std::max(tmp,dp[R2][0]);
        }
    }
    printf("%lld\n",ans);
//	return 0;
}
    
posted @ 2018-04-03 07:33  zzzzx  阅读(115)  评论(0编辑  收藏  举报