Bzoj 1040 [ZJOI2008]骑士 题解

1040: [ZJOI2008]骑士

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 5368  Solved: 2044
[Submit][Status][Discuss]

Description

  Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各
界的赞扬。最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境
中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一
个真龙天子的降生,带领正义打败邪恶。骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一
些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出
征的。战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有
的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的
情况),并且,使得这支骑士军团最具有战斗力。为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战
斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。

Input

  第一行包含一个正整数N,描述骑士团的人数。接下来N行,每行两个正整数,按顺序描述每一名骑士的战斗力
和他最痛恨的骑士。

Output

  应包含一行,包含一个整数,表示你所选出的骑士军团的战斗力。

Sample Input

3
10 2
20 3
30 1

Sample Output

30

HINT 

N ≤ 1 000 000,每名骑士的战斗力都是不大于 1 000 000的正整数。

  在开头先吐槽一下题面,”劫富济贫“是怎么得到社会"各界"的好评的?!  开个玩笑,这道题可以说是Bzoj1214枪战Maf的加强版没做过的可以先去做一下(附题解: [POI2008]枪战Maf题解)。
  对于这道题的种种性质我就不多说了,在那篇题解里基本都分析了。
  这两道题最大的不同就是这道题并不能用贪心做,也就是我们并不能再通过拓扑去得到答案。而是利用他的另一个性质:树。
  我们可以注意到,只要我们缩一下边,那么留给我们的就是一个树,或者树林,那么对于树的叶子节点,他们一定只是由一个骑士组成,所以我们只要简单的用两种状态记录一下选他和不选他的答案就好了。当我们爬到树根时,我们不必急着直接转移给他,而是转移给实际向该叶节点伸边的那个骑士,然后再环中随便找一个点开始一个dfs,反正只是简单环,出不了什么问题。再记录一下结算到但钱违者当前这个环你的切入点是否被选上然后在绕回来时转移给大点就好了。
  
  1 #include <cstdlib>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <string>
  5 #include <queue>
  6 #include <algorithm>
  7 #include <cmath>
  8 #include <map>
  9 #define N 1000005
 10 using namespace std;
 11 int n,to[N],zz1,zz,a[N],b[N];
 12 long long va[N],vva[N];
 13 struct ro
 14 {
 15     int to,next,fr;
 16 }road2[N],road[N];
 17 void build2(int x,int y)
 18 {
 19     zz1++;
 20     road2[zz1].to=y;
 21     road2[zz1].next=b[x];
 22     b[x]=zz1;
 23 }
 24 void build(int x,int y,int z)
 25 {
 26     zz++;
 27     road[zz].fr=z;
 28     road[zz].to=y;
 29     road[zz].next=a[x];
 30     a[x]=zz;
 31 }
 32 int dfn[N],low[N],zz2,zz3,top,st[N],bel[N],sta[N],fa[N],size[N];
 33 bool rd[N],rd2[N];
 34 void tar(int x)
 35 {
 36     zz2++;top++;
 37     st[top]=x;
 38     dfn[x]=low[x]=zz2;
 39     rd[x]=rd2[x]=1;
 40     for(int i=b[x];i>0;i=road2[i].next)
 41     {
 42         int y=road2[i].to;
 43         if(!rd2[y])
 44         {
 45             tar(y);
 46             low[x]=min(low[x],low[y]);
 47         }
 48         else if(rd[y])
 49         {
 50             low[x]=min(dfn[y],low[x]);
 51         }
 52     }
 53     if(dfn[x]==low[x])
 54     {
 55         zz3++;
 56         int v;
 57         do{
 58             v=st[top];
 59             rd[v]=0;
 60             top--;
 61             bel[v]=zz3;
 62             sta[zz3]=v;
 63             size[zz3]++;
 64             vva[zz3]+=va[v];
 65         }while(dfn[v]!=low[v]);
 66     }
 67 }
 68 long long f[N][2],f2[N][2][2],f3[N][2];
 69 void dfs2(int x,int fr,int tp)
 70 {
 71     if(x==tp&&fr)
 72     {
 73         f2[x][0][0]=max(f2[fr][1][0],f2[fr][0][0]);
 74         f2[x][1][1]=f2[fr][0][1];
 75         f[bel[x]][0]=max(f2[x][0][0],f2[x][1][1]);
 76         return;
 77     }
 78     if(x==tp)
 79     {
 80         f2[x][0][0]+=f3[x][0];
 81         f2[x][1][1]+=f3[x][1];
 82         f2[x][1][1]+=va[x];
 83     }
 84     else
 85     {
 86         if(fr==tp)
 87         {
 88             f2[x][0][0]=f2[x][1][0]=f2[fr][0][0],f2[x][0][1]=f2[fr][1][1];
 89             f2[x][1][0]+=f3[x][1];f2[x][1][0]+=va[x];
 90             f2[x][0][1]+=f3[x][0];f2[x][0][0]+=f3[x][0];
 91         }
 92         else
 93         {
 94             f2[x][0][0]=max(f2[fr][1][0],f2[fr][0][0]);
 95             f2[x][0][1]=max(f2[fr][1][1],f2[fr][0][1]);
 96             f2[x][1][0]=f2[fr][0][0];
 97             f2[x][1][1]=f2[fr][0][1];
 98             f2[x][1][0]+=va[x]+f3[x][1];
 99             f2[x][1][1]+=va[x]+f3[x][1];
100             f2[x][0][0]+=f3[x][0];
101             f2[x][0][1]+=f3[x][0];
102         }
103     }
104     dfs2(to[x],x,tp);
105 }
106 void dfs1(int x)
107 {
108     for(int i=a[x];i>0;i=road[i].next)
109     {
110         int y=road[i].to;
111         dfs1(y);
112         if(size[x]==1)
113         {
114             f[x][0]+=max(f[y][0],f[y][1]);
115             f[x][1]+=f[y][0];
116         }
117         else
118         {
119             f3[road[i].fr][0]+=max(f[y][0],f[y][1]);
120             f3[road[i].fr][1]+=f[y][0];
121         }
122     }
123     if(size[x]==1)f[x][1]+=vva[x];
124     else
125     {
126         dfs2(sta[x],0,sta[x]);
127     }
128 }
129 int main()
130 {
131     scanf("%d",&n);
132     for(int i=1;i<=n;i++)
133     {
134         scanf("%lld%d",&va[i],&to[i]);
135         build2(to[i],i);
136     }
137     for(int i=1;i<=n;i++)
138     {
139         if(!rd2[i])tar(i);
140     }
141     for(int i=1;i<=n;i++)
142     {
143         for(int j=b[i];j>0;j=road2[j].next)
144         {
145             int y=road2[j].to;
146             if(bel[i]!=bel[y])
147             {
148                 build(bel[i],bel[y],i);
149             }
150         }
151     }
152     for(int i=1;i<=zz3;i++)
153     {
154         if(size[i]!=1)
155         {
156             dfs1(i);
157         }
158     }
159     long long ans=0;
160     for(int i=1;i<=zz3;i++)
161     {
162         if(size[i]!=1)
163         {
164             ans+=f[i][0];
165         }
166     }
167     printf("%lld\n",ans);
168     return 0;
169 }
View Code

转载于:https://www.cnblogs.com/liutianrui/p/7674106.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值