每个点出度都为1,可以发现这张图其实是个环套树森林,树中儿子指向父亲,环上边同向。

  首先自环肯定是没救的,先抬出去。

  要使死亡人数最多的话,显然若一个点入度为0其不会死亡,而一个孤立的环至少会留下一个点。对于环套树,若某个点有子树,可以以瞄准它的点为起点,每个点都被在环上瞄准他的点所击中。这样就剩下了很多棵树,除叶子节点的点都会死亡。

  死亡人数最少似乎同样可以贪心,虽然我没这么写。可以发现最后存活下来的人之间一定不存在瞄准关系,否则必有一个死亡。并且只要最后存活下来的人之间不存在瞄准关系(且不被瞄准的存活),一定有方案使这些人最终存活下来,对于一个连通块人的死亡只要按照拓扑逆序开枪即可(使孤立环全部死亡是办不到的,但显然要使死亡人数最少我们不会这样干)。于是求一下环套树的包含所有叶子节点的最大独立集即可。

  细节挺多,在luoguA了,bzoj跑了好长时间之后wa掉了,不知道哪写挂了啊。

  upd:发现是一些奇怪的地方爆了int……现在A掉辣!

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 1000010
int n,a[N],id[N],degree[N],dfn[N],low[N],stk[N],set[N],size[N];
int top=,cnt=,t=;
long long ans1=,ans2=,f[N][],g[N][][];
bool flag[N],isroot[N];
int p[N];
struct data{int to,nxt;
}edge[N];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void tarjan(int k)
{
dfn[k]=low[k]=++cnt;
stk[++top]=k;flag[k]=;
if (a[a[k]]!=a[k])
if (!dfn[a[k]]) tarjan(a[k]),low[k]=min(low[k],low[a[k]]);
else if (flag[a[k]]) low[k]=min(low[k],dfn[a[k]]);
if (dfn[k]==low[k])
{
t++;
while (stk[top]!=k)
{
set[stk[top]]=t;
size[t]++;
flag[stk[top]]=;
top--;
}
set[k]=t;size[t]++;flag[k]=;top--;
}
}
void dfs(int k)
{
f[k][]=,f[k][]=;
if (!degree[k]) f[k][]=-n;
for (int i=p[k];i;i=edge[i].nxt)
if (size[set[edge[i].to]]==)
{
dfs(edge[i].to);
f[k][]+=max(f[edge[i].to][],f[edge[i].to][]);
f[k][]+=f[edge[i].to][];
}
}
int main()
{
n=read();
for (int i=;i<=n;i++)
{
a[i]=read();
if (a[i]==i) ans1++;
else degree[a[i]]++;
}
for (int i=;i<=n;i++)
if (!dfn[i]&&a[i]!=i) tarjan(i);
for (int i=;i<=n;i++)
if (degree[i]&&size[set[i]]==) ans1++;
memset(flag,,sizeof(flag));
for (int i=;i<=n;i++)
if (size[set[i]]>&&degree[i]>) flag[set[i]]=;
for (int i=;i<=t;i++)
if (size[i]>) ans1+=size[i]-+flag[i];
t=;
for (int i=;i<=n;i++)
if (a[i]!=i) addedge(a[i],i);
for (int i=;i<=n;i++)
if (size[set[i]]>||a[a[i]]==a[i]&&a[i]!=i) isroot[i]=;
for (int i=;i<=n;i++)
if (isroot[i]) dfs(i);
memset(dfn,,sizeof(dfn));
for (int i=;i<=n;i++)
if (isroot[i]&&!dfn[i])
if (a[a[i]]==a[i]) ans2+=max(f[i][],f[i][]);
else
{
int x=i,t=;
while (a[x]!=i) dfn[x=a[x]]=,id[++t]=x;
id[++t]=i;dfn[i]=;
for (int j=;j<=t;j++) g[i][][]=g[i][][]=g[i][][]=g[i][][]=;
g[][][]=f[id[]][],g[][][]=f[id[]][];
g[][][]=g[][][]=-n;
for (int j=;j<=t;j++)
{
g[j][][]=max(g[j-][][],g[j-][][])+f[id[j]][];
g[j][][]=max(g[j-][][],g[j-][][])+f[id[j]][];
g[j][][]=g[j-][][]+f[id[j]][];
g[j][][]=g[j-][][]+f[id[j]][];
}
ans2+=max(g[t][][],max(g[t][][],g[t][][]));
}
ans2=n-ans2;
cout<<ans2<<' '<<ans1;
return ;
}

BZOJ1124 POI2008枪战Maf(环套树+贪心)的更多相关文章

  1. BZOJ1124 [POI2008]枪战Maf[贪心(证明未完成)+拓扑排序]

    吐槽:扣了几个小时,大致思路是有了,但是贪心的证明就是不会, 死磕了很长时间,不想想了,结果码代码又不会码.. 深深体会到自己码力很差,写很多行还没写对,最后别人代码全一二十行,要哭了 以下可能是个人 ...

  2. bzoj1124[POI2008]枪战maf

    这代码快写死我了.....死人最多随便推推结论.死人最少,每个环可以单独考虑,每个环上挂着的每棵树也可以分别考虑.tarjan找出所有环,对环上每个点,求出选它和不选它时以它为根的树的最大独立集(就是 ...

  3. BZOJ 1124: [POI2008]枪战Maf(构造 + 贪心)

    题意 有 \(n\) 个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪. 因此,对于不同的开枪顺序,最后死的人也不同. 问最 ...

  4. 【BZOJ 1124】[POI2008] 枪战Maf Tarjan+树dp

    #define int long long using namespace std; signed main(){ 这个题一看就是图论题,然后我们观察他的性质,因为一个图论题如果没有什么性质,就是真· ...

  5. 【BZOJ1124】[POI2008]枪战Maf 贪心+思路题

    [BZOJ1124][POI2008]枪战Maf Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开 ...

  6. bzoj 1124 [POI2008]枪战Maf 贪心

    [POI2008]枪战Maf Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 741  Solved: 295[Submit][Status][Disc ...

  7. BZOJ 1124: [POI2008]枪战Maf

    1124: [POI2008]枪战Maf Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 617  Solved: 236[Submit][Status ...

  8. [POI2008]枪战Maf题解

    问题 C: [POI2008]枪战Maf 时间限制: 1 Sec  内存限制: 256 MB 题目描述 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺 ...

  9. [POI2008]枪战Maf

    [POI2008]枪战Maf 题目 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的 ...

随机推荐

  1. java线程状态和获取线程基本信息

    1. 线程状态 新生状态 用 new 关键字建立一个线程后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start()方法进入就绪状态. 就绪状态 处于就绪状态线程具备了运行 ...

  2. Zephyr的Logging

    1 前言 刚接触Zephyr,两眼一抹黑,光是阅读代码对系统没什么概念.还需要通过一些日志了解系统的运行机制,以及各种内核行为. 这就需要借助系统的Logging,大体分为两部分System Logg ...

  3. java算法----排序----(4)快速排序

    package log; public class Test4 { /** * java算法---快速排序 * * @param args */ public static void main(Str ...

  4. Luogu1967 NOIP2013 货车运输 最大生成树、倍增

    传送门 题意:给出一个$N$个节点.$M$条边的图,$Q$次询问,每一次询问两个点之间的所有可行路径中经过的边的边权的最小值中的最大值.$N \leq 10000 , M \leq 50000 , Q ...

  5. 【精】【入门篇】js正则表达式

    前言 最近有了点时间,就回头看了一下<学习正则表达式>这本书.怎么说呢,这本书适合从零开始学习正则表达式或者有一点基础但是想要加强这方面能力的读者.这本书的风格是“实践出真知”,使用归纳方 ...

  6. 全景3d

    Three.js Tour.js Run.js 3D Css3 酷家乐:https://www.kujiale.com/ 爱空间:http://bj.ikongjian.com/?utm_source ...

  7. Individual Project - Word frequency program——12061154Joy

    Description&Requirement: http://www.cnblogs.com/jiel/p/3978727.html 项目时间估计 理解项目要求: 1h 构建项目逻辑: 1h ...

  8. Personal Reading Assignment 2 -读推荐文章有感以及项目开发目前总结

    在经过个人作业和结对作业的磨练和现在正在进行的团队作业的考验中,我对自己软件开发的一点得失有了些许感悟,同时读了老师推荐的文章后,自己也是有了一些感受. 首先在“No Silver Bullet”一文 ...

  9. Scrum Meeting 6

                第六次会议 由于之前队员一直在做数据库和编译大作业,课业压力较大,所以软工进度往后拖了好多. No_00:工作情况 No_01:任务说明 待完成 已完成 No_10:燃尽图 N ...

  10. 软件工程(四)数据流图DFD

    结构化分析中,常用到数据模型为实体关系图,功能模型是数据流图 DFD 可以认为,一个基于计算机的信息处理系统由数据流和一系列的转换构成,这些转换将输入数据流变换为输出数据流.数据流图就是用来刻画数据流 ...