骑士 树上+环上dp
这题我最大的收获是不要轻易相信网上的blog的题解...
环上dp 应该是两维,不能一维 (一下午的崩溃啊)
先求出环上每个点选和不选的最大值
再枚举环上那个点选不选(枚举相邻两个就行)
进行dp
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* 我现在只想日死那个一维f[]的人 环上dp需要f[N][2]... */ #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; inline int read() { char q=getchar();int ans=0,flag=1; while(q<'0'||q>'9'){if(q=='-')flag=-1;q=getchar();} while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();} return ans*flag; } const int N=1000006; inline ll maxn(ll a,ll b){return a>b?a:b;} struct son { int v,next; }a1[N*2]; int first[N*2],e; void addbian(int u,int v) { a1[e].v=v; a1[e].next=first[u]; first[u]=e++; } int n; int nx[N],ind[N]; int v[N]; ll g[N][2]; int dfn[N],low[N],zhan[N],he,tim,dui[N],sum,size[N]; bool flag[N]; bool vis[N]; ll t[N][2]; int con; ll f[N][2]; ll get(int begg,int endd) { con=0; for(int i=begg;i!=endd;i=nx[i]) { ++con; vis[i]=1; t[con][0]=g[i][0]; t[con][1]=g[i][1]; } f[0][0]=f[0][1]=0; f[1][0]=t[1][0];f[1][1]=t[1][1]; for(int i=2;i<=con;++i) { f[i][1]=f[i-1][0]+t[i][1]; f[i][0]=maxn(f[i-1][1],f[i-1][0])+t[i][0]; } return maxn(f[con][0],f[con][1]); } int fa[N]; void dp(int x) { g[x][0]=0;g[x][1]=v[x]; int temp; for(int i=first[x];i!=-1;i=a1[i].next) { temp=a1[i].v; if(temp==fa[x]||size[dui[temp]]>1) continue; fa[temp]=x; dp(temp); g[x][0]+=maxn(g[temp][0],g[temp][1]); g[x][1]+=g[temp][0]; } } void tarjan(int x) { dfn[x]=low[x]=++tim; zhan[++he]=x;flag[x]=1; int temp; for(int i=first[x];i!=-1;i=a1[i].next) { temp=a1[i].v; if(dfn[temp]==-1) { tarjan(temp); low[x]=min(low[x],low[temp]); } else if(flag[temp]) low[x]=min(low[x],low[temp]); } if(low[x]==dfn[x]) { ++sum; while(1) { temp=zhan[he--];flag[temp]=0; dui[temp]=sum; ++size[sum]; if(temp==x) break; } } } ll work() { ll ans=0,t1,t2; he=0; for(int i=1;i<=n;++i) if(dfn[i]==-1) tarjan(i); for(int i=1;i<=n;++i) if(size[dui[i]]>1) { fa[i]=-1; dp(i); } for(int i=1;i<=n;++i) if(size[dui[i]]>1&&!vis[i]) { t1=g[i][0]+get(nx[i],i); t2=g[nx[i]][0]+get(nx[nx[i]],nx[i]); ans+=maxn(t1,t2); } return ans; } int main(){ //freopen("in.in","r",stdin); mem(first,-1); mem(dfn,-1); scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d%d",&v[i],&nx[i]); ++ind[nx[i]]; addbian(nx[i],i); } cout<<work(); }
本来还觉得这道题跟maf枪战一样呢
还应用了贪心+一些之前做过的题的技巧,打了半天wa了6个点....