bzoj 1040: [ZJOI2008]骑士
Posted lxy8584099
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1040: [ZJOI2008]骑士相关的知识,希望对你有一定的参考价值。
和仙人掌有所不同? 应该是一样的啊。。。
/************************************************************** Problem: 1040 User: lxy8584099 Language: C++ Result: Accepted Time:1916 ms Memory:40868 kb ****************************************************************/ // by pig~~ #include<cstdio> #include<cstring> #define ll long long using namespace std; /* 思路: 因为每个人只有一个特别讨厌的人 所以建边后 肯定成环或者是单独一个点(看作环) 对每个环进行DP 每次DP后最大值累加起来 */ const int N=1000050; struct pp{int nxt,to;}e[N<<1]; int n,tot,val[N],head[N],u1,u2,E; ll ans,f[N][2];// f[i][0/1] 表示 不取/取 这个点的最大值 bool vis[N]; inline void add(int u,int v){e[tot].nxt=head[u];e[tot].to=v;head[u]=tot++;} inline ll max(ll a,ll b){return a>b?a:b;} inline ll min(ll a,ll b){return a>b?b:a;} inline void dfs(int u,int last) { vis[u]=1; for(int j=head[u];~j;j=e[j].nxt) { if((j^1)==last) continue; // 去掉返回边,不走回头路 int v=e[j].to; if(vis[v]) { u1=u;u2=v;E=j;continue; // 找到环 选择切断的边 E,俩断点 u1,u2 } dfs(v,j); } } inline void DP(int u,int last) { f[u][0]=0;f[u][1]=val[u]; for(int j=head[u];~j;j=e[j].nxt) { if(((j^1)==last)||(j==E)||((j^1)==E)) continue; // 去掉返回边,不走我们选择断掉的路 int v=e[j].to; DP(v,j); f[u][1]+=f[v][0]; f[u][0]+=max(f[v][1],f[v][0]); } } int main() { // freopen("knight.in","r",stdin); // freopen("knight.out","w",stdout); memset(head,-1,sizeof(head)); scanf("%d",&n); for(int i=1,v;i<=n;i++) { scanf("%d%d",&val[i],&v);add(i,v);add(v,i);//建边 从0开始 用位运算方便求出同边 } for(int i=1;i<=n;i++) { if(vis[i]) continue; dfs(i,-2);ll all; /* 本次DP的答案在f[u1][0] 或 f[u2][0] 中 因为f[u1][1]的结果可能会包含取到 u2 , 同理 f[u2][1]的结果可能会包含取到 u1. */ DP(u1,-1); all=f[u1][0]; DP(u2,-1); all=max(all,f[u2][0]); ans+=all; } printf("%lld ",ans); return 0; } /* 3 20 3 20 3 30 1 */
以上是关于bzoj 1040: [ZJOI2008]骑士的主要内容,如果未能解决你的问题,请参考以下文章