每个点出度都为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. 利用 ProtoThreads实现Arduino多线程处理(1)

    转载请注明:@小五义http://www.cnblogs.com/xiaowuyiQQ群:64770604 这几天和群里小V同学讨论一个项目时,偶然发现了 ProtoThreads,简称PT,用其来实 ...

  2. 分布式RPC框架性能大比拼 dubbo、motan、rpcx、gRPC、thrift的性能比较

    Dubbo 是阿里巴巴公司开源的一个Java高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成.不过,略有遗憾的是,据说在淘宝内部,dub ...

  3. three.js - 渲染并展示三维对象

    看结果: 看源码及解释: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...

  4. Python 爬取 11 万 Java 程序员信息竟有这些重大发现!

    一提到程序猿,我们的脑子里就会出现这样的画面: 或者这样的画面: 心头萦绕的字眼是:秃头.猝死.眼镜.黑白 T 恤.钢铁直男-- 而真实的程序猿们,是每天要和无数数据,以及数十种编程语言打交道.上能手 ...

  5. SerialPort.h SerialPort.cpp

    SerialPort.h 1 #ifndef __SERIALPORT_H__ 2 #define __SERIALPORT_H__ 3 4 #define WM_COMM_BREAK_DETECTE ...

  6. web service 框架

    WebService简介 Web Service技术, 能使得运行在不同机器上的不同应用无须借助附加的.专门的第三方软件或硬件, 就可相互交换数据或集成.依据Web Service规范实施的应用之间, ...

  7. NPOI导Excel样式设置

    一.创建一个Excel //创建一个工作簿 XSSFWorkbook workbook = new XSSFWorkbook(); //创建一个页 ISheet sheet = workbook.Cr ...

  8. hibernate 解决 java.lang.NoClassDefFoundError: org/hibernate/cfg/Configuration

    参考:https://stackoverflow.com/questions/9851528/java-lang-noclassdeffounderror-org-hibernate-cfg-conf ...

  9. python语言程序设计?

    1, 别说了,我还是有几分蛋疼的.女朋友..计算机..唉 2, 今天把那几个练习写完吧? 3, 这个注释有啥用最前面的?? 4, 我在学完python后必须学完C和C++并开始离散数学和线代高数等全复 ...

  10. JVM规范系列第5章:加载、链接与初始化

    加载是根据特定名称查找类或接口类型的二进制表示(Binary Representation),并由此二进制表示创建类或接口的过程. 加载,就是指去寻找类或接口的过程. 链接是为了让类或接口可以被 Ja ...