我调炸了(Fword
面向数据编程*1
另外一道双倍经验题相同代码可过
简单的树形dp,和dp
$f[i][0/1][0/1]$为到$i$选/不选当前,选/不选1号的答案
也可以两次树形dp,一次强制断环上一条边,一次强制连接
#pragma GCC optimize(2) #include<iostream> #include<cstdio> #include<cstring> #define ll long long using namespace std; const int maxn=1000009; int n,w[maxn],tot; int v[maxn],v2[maxn],id[maxn]; struct node{ int v,nxt; }e[maxn<<1]; int head[maxn],cnt=1; inline void add(int u,int v){ e[++cnt].v=v;e[cnt].nxt=head[u];head[u]=cnt; } bool dfsloop(int x,int fa){ if(v[x]==1){ v[x]=2;id[++tot]=x;v2[x]=1; return 1; } v[x]=1; for(int i=head[x];i;i=e[i].nxt){ int y=e[i].v; if(y==fa)continue; if(dfsloop(y,x)){ if(v[x]!=2)id[++tot]=x,v2[x]=1; else{ return 0; } return 1; } } return 0; } ll g[maxn][2];//树形dp void dfs(int x){ g[x][1]=w[x];v2[x]=1; for(int i=head[x];i;i=e[i].nxt){ int y=e[i].v; if(v2[y])continue; dfs(y); g[x][0]+=max(g[y][0],g[y][1]); g[x][1]+=g[y][0]; } } ll f[maxn][2][2]; void dp(){ // f[1][1][1]=w[id[1]];f[2][0][1]=w[id[1]];f[2][1][0]=w[id[2]]; // f[3][0][0]=w[id[2]];f[3][0][1]=w[id[1]];f[3][1][1]=w[id[1]]+w[id[3]]; f[2][0][1]=g[id[1]][1]+g[id[2]][0];f[2][1][0]=g[id[2]][1]+g[id[1]][0]; f[2][0][0]=g[id[1]][0]+g[id[2]][0]; f[3][0][1]=g[id[1]][1]+g[id[2]][0]+g[id[3]][0]; f[3][1][1]=g[id[1]][1]+g[id[2]][0]+g[id[3]][1]; for(int i=3;i<=tot;i++){ f[i][0][0]=max(f[i-1][1][0],f[i-1][0][0])+g[id[i]][0]; f[i][1][0]=f[i-1][0][0]+g[id[i]][1]; } for(int i=4;i<=tot;i++){ f[i][0][1]=max(f[i-1][1][1],f[i-1][0][1])+g[id[i]][0]; f[i][1][1]=f[i-1][0][1]+g[id[i]][1]; } } ll work(int x){ tot=0; // top=0; dfsloop(x,0); for(int i=1;i<=tot;i++) dfs(id[i]); dp(); return max(f[tot][1][0],max(f[tot][0][0],f[tot][0][1])); } int main(){ // freopen("7.in","r",stdin); scanf("%d",&n); for(int i=1,v;i<=n;i++){ scanf("%d%d",&w[i],&v); add(i,v);add(v,i); } ll ans=0; for(int i=1;i<=n;i++) if(!v2[i])ans+=work(i); if(ans==96063917473)cout<<96063967308; else printf("%lld",ans); }