每个点出度都为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. Android学习之基础知识七—碎片的最佳实践

    一.Android碎片(Fragment)的最佳实践——简易版新闻应用 第一步:新建FragmentBestPractice项目,在app/build.gradle当中添加:RecyclerView ...

  2. SkylineGlobe 如何使用二次开发接口创建粒子效果

    SkylineGlobe在6.6版本,ICreator66接口新增加了CreateEffect方法,用来创建粒子效果对象: 以及ITerrainEffect66对象接口,可以灵活设置粒子效果对象的相关 ...

  3. [10] AOP的注解配置

    1.关于配置文件 首先在因为要使用到扫描功能,所以xml的头文件中除了引入bean和aop之外,还要引入context才行: <?xml version="1.0" enco ...

  4. SPOJ GSS(Can you answer the Queries)系列 7/8

    GSS1 线段树最大子段和裸题,不带修改,注意pushup. 然而并不会猫树之类的东西 #include<bits/stdc++.h> #define MAXN 50001 using n ...

  5. 10个Chrome基础使用技巧

    Chrome是前端开发中最常用到的一个浏览器,本文整理了Chrome的10个基础使用技巧(Chrome中有很多和Sublime Text2类似的快捷键).如果有其它本文未提及的实用的小技巧,也可以留言 ...

  6. Maven私有仓库: 发布release版本报错:Return code is: 400, ReasonPhrase: Repository does not allow upd ating assets: maven-releases.

    今天在将一个maven组件由SNAPSHORT升级为正式版本1.0.0,然后执行发布: mvn clean deploy -pl ielong-common -am -DskipTests, 报错:R ...

  7. kafka学习2:kafka集群安装与配置

    在前一篇:kafka学习1:kafka安装 中,我们安装了单机版的Kafka,而在实际应用中,不可能是单机版的应用,必定是以集群的方式出现.本篇介绍Kafka集群的安装过程: 一.准备工作 1.开通Z ...

  8. 【php增删改查实例】第十二节 - 数据删除功能

    1.单条数据删除 思路:首先,需要也只能允许用户勾选一条数据,然后弹出一个确认框,问用户是否真的要删除?如果是,就把ID传递到PHP,然后写一个delete语句,通过ID去删除即可. 画好了按钮之后, ...

  9. (一)ABP添加控制器和页面(有时候页面不出来)

    1:添加控制器后需要写[Area("AppAreaName")] 2:继承  WebControllerBase 3:创建视图就可以出现index页面了

  10. [UWP 自定义控件]了解模板化控件(2.1):理解ContentControl

    UWP的UI主要由布局容器和内容控件(ContentControl)组成.布局容器是指Grid.StackPanel等继承自Panel,可以拥有多个子元素的类.与此相对,ContentControl则 ...