luogu P2607 [ZJOI2008]骑士
题面传送门
显然基环树dp
对于每个联通块找到环然后强制选和不选累计答案即可。
代码实现:
#include<cstdio>
#include<cstring>
#include<queue>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,a[1000039],b[1000039],in[1000039],flag[1000039],root;
long long dp[1000039][2],ans,tot;
struct yyy{int to,z,flag;};
struct ljb{
int head,h[1000039];
yyy f[1000039];
inline void add(int x,int y){
f[++head]=(yyy){y,h[x]};
h[x]=head;
}
}s;
queue<int > q;
inline void dfs(int x){
flag[x]=1;
int cur=s.h[x];
yyy tmp;
dp[x][1]=a[x];dp[x][0]=0;
while(cur!=-1){
tmp=s.f[cur];
if(tmp.to!=root){
dfs(tmp.to);
dp[x][1]+=dp[tmp.to][0];
dp[x][0]+=max(dp[tmp.to][0],dp[tmp.to][1]);
}
else dp[x][1]=-1e9;
cur=tmp.z;
}
}
int main(){
memset(s.h,-1,sizeof(s.h));
register int i;
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]),s.add(b[i],i),in[a[i]]++;
for(i=1;i<=n;i++){
if(!flag[i]){
root=i;
flag[i]=1;
while(!flag[b[root]]) flag[b[root]]=1,root=b[root];
dfs(root);
tot=max(dp[root][1],dp[root][0]);
root=b[root];
flag[root]=1;
dfs(root);
ans+=max(tot,max(dp[root][1],dp[root][0]));
}
}
printf("%lld\n",ans);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步