这代码快写死我了.....死人最多随便推推结论。死人最少,每个环可以单独考虑,每个环上挂着的每棵树也可以分别考虑.tarjan找出所有环,对环上每个点,求出选它和不选它时以它为根的树的最大独立集(就是最多活下来的人数),然后环上每个点选或不选对应的是一个“价值”,这个价值是那个点挂着的树里最多存活人数。先全都不选环上的点,算出选和不选时最大独立集的差值,问题变成有一个环,环上有一堆数(那些差值),选出一些不相邻的数使得和最大,然后我按着bzoj2151种树写了个贪心....这个贪心的思路也很神,网上有很多题解.后来发现这个东西和“种树”还不一样,因为种树限制必须种m棵,这个选的个数不限,所以可以O(nlogn)降到O(n),不过这两种方法都能过。另外tarjan不加inline会RE.总之这个方法不太具备可写性.

UPD:现在发现我当时是把这题写成bzoj1040了,囧。

#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
const int maxn=1500005;
int aim[maxn];
struct edge{//反向建边
    int to,next;
}lst[maxn],lst2[maxn];int len=1,len2=1;
int first[maxn],first2[maxn];
void addedge(int a,int b){
    lst[len].to=b;
    lst[len].next=first[a];
    first[a]=len++;
}
void addedge2(int a,int b){
    lst2[len2].to=b;
    lst2[len2].next=first2[a];
    first2[a]=len2++;
}
int T;
int s[maxn],low[maxn],dfn[maxn],indeg[maxn],top;
int belong[maxn],sz[maxn],cnt;
bool ins[maxn];
inline void tarjan(int x){
    dfn[x]=low[x]=++T;
    s[top++]=x;ins[x]=true;
    if(!dfn[aim[x]]){
        tarjan(aim[x]);
        if(low[aim[x]]<low[x])low[x]=low[aim[x]];
    }else if(ins[aim[x]]&&dfn[aim[x]]<low[x])low[x]=dfn[aim[x]];
    if(low[x]==dfn[x]){
        ++cnt;
        do{
            ins[s[--top]]=false;
            belong[s[top]]=cnt;
            sz[cnt]++;
            addedge2(cnt,s[top]);
        }while(s[top]!=x);
    }
}
bool die[maxn];
int f[2][maxn];//bool vis[2][maxn];//f[][]求活人数目
int max(int a,int b){
    return a>b?a:b;
}
int q[maxn];bool vis[maxn];
void dp(int s){
    int head=0,tail=0;
    if(vis[s])return;
    q[tail++]=s;
    while(head!=tail){
        int x=q[head++];vis[x]=true;
        for(int pt=first[x];pt;pt=lst[pt].next){
            if(!vis[lst[pt].to])q[tail++]=lst[pt].to;
        }
    }
    for(int i=tail-1;i>=0;--i){
        int x=q[i];
        f[1][x]=1;
        for(int pt=first[x];pt;pt=lst[pt].next){
            if(belong[lst[pt].to]==belong[x])continue;
            f[1][x]+=f[0][lst[pt].to];
            if(die[lst[pt].to])f[0][x]+=f[0][lst[pt].to];
            else f[0][x]+=max(f[0][lst[pt].to],f[1][lst[pt].to]);
        }
    }
}
int w[maxn];/*
int work(int num){//第num个SCC最多生还多少人。种树???
    ++T;
    priority_queue<node> q;
    int ans=0;//猜测SCC节点出栈是按照在环上的顺序
    for(int i=1;i<=sz[num];++i){
        nxt[i]=i+1;
        pre[i]=i-1;
    }
    nxt[sz[num]]=1;pre[1]=sz[num];
    int j=0;
    for(int pt=first2[num];pt;pt=lst2[pt].next){
         
        ans+=f[0][lst2[pt].to];
        if(!die[lst2[pt].to])w[++j]=f[1][lst2[pt].to]-f[0][lst2[pt].to];
        else w[++j]=0;
        q.push(node(j));
    }//for(int i=1;i<=j;++i)printf("%d ",w[i]);printf("\n");
    while(!q.empty()){//最后一次拿出来的时候会出错吗?
        node tmp=q.top();q.pop();
        if(used[tmp.k]==T)continue;
        if(w[tmp.k]<=0)break;
        ans+=w[tmp.k];//printf("%d %d\n",tmp.k,w[tmp.k]);
        w[tmp.k]=w[pre[tmp.k]]+w[nxt[tmp.k]]-w[tmp.k];//printf("w%d\n",w[tmp.k]);
        used[pre[tmp.k]]=used[nxt[tmp.k]]=T;
        if(pre[tmp.k]==nxt[tmp.k])break;
        pre[tmp.k]=pre[pre[tmp.k]];nxt[tmp.k]=nxt[nxt[tmp.k]];
        if(used[pre[tmp.k]]==T||used[nxt[tmp.k]]==T)break;
        pre[nxt[tmp.k]]=tmp.k;nxt[pre[tmp.k]]=tmp.k;// printf("%d %d %d %d\n",w[1],w[2],w[3],w[4]);
        q.push(node(tmp.k));
    }//printf("%d\n",ans);
    return ans;
}*/
int F[2][2][maxn];
int work(int num){
    int j=0,ans=0;
    for(int pt=first2[num];pt;pt=lst2[pt].next){
        ans+=f[0][lst2[pt].to];
        if(!die[lst2[pt].to])w[++j]=f[1][lst2[pt].to]-f[0][lst2[pt].to];
        else w[++j]=0;
    }
    F[1][1][1]=w[1];F[0][0][1]=0;F[0][1][1]=F[1][0][1]=-0x3f3f3f3f;
    for(int i=2;i<=j;++i){
        F[0][1][i]=F[0][0][i-1]+w[i];
        F[1][1][i]=F[1][0][i-1]+w[i];
        F[0][0][i]=max(F[0][0][i-1],F[0][1][i-1]);
        F[1][0][i]=max(F[1][0][i-1],F[1][1][i-1]);
    }
    return ans+max(F[0][0][j],max(F[0][1][j],F[1][0][j]));
}
int main(){
    int n;scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d",aim+i);
        //if(i==aim[i])die[i]=true;
        //else
         addedge(aim[i],i);
    }
    for(int i=1;i<=n;++i){
        if(!dfn[i])tarjan(i);
    }
    for(int i=1;i<=n;++i){
        if(belong[i]!=belong[aim[i]])indeg[belong[aim[i]]]++;
        if(i==aim[i])indeg[belong[i]]++;
    }
    for(int i=1;i<=n;++i){
        if(!first[i]){
            die[aim[i]]=true;
        }
    }
    for(int i=1;i<=n;++i){
        dp(i);
    }
    int ans1=n;
    for(int i=1;i<=n;++i){
        if(aim[i]==i){
            ans1-=f[0][i];
        }
    }
    for(int i=1;i<=cnt;++i){
        if(sz[i]>1){
            ans1-=work(i);
        }
    }
    int ans2=n;
    for(int i=1;i<=cnt;++i){
        if(!indeg[i])ans2--;
    }
    printf("%d %d\n",ans1,ans2);
    return 0;
}

  

bzoj1124[POI2008]枪战maf的更多相关文章

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

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

  2. BZOJ1124 POI2008枪战Maf(环套树+贪心)

    每个点出度都为1,可以发现这张图其实是个环套树森林,树中儿子指向父亲,环上边同向. 首先自环肯定是没救的,先抬出去. 要使死亡人数最多的话,显然若一个点入度为0其不会死亡,而一个孤立的环至少会留下一个 ...

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

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

  4. BZOJ 1124: [POI2008]枪战Maf

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

  5. [POI2008]枪战Maf

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

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

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

  7. [POI2008]枪战Maf题解

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

  8. 【BZOJ1124】[POI2008]枪战Maf(基环树_构造)

    被教练勒令做题不能看题解后的第一道新题,自行 yy 了好久终于 AC 了(菜啊)--写博客纪念. 题目: BZOJ1124 分析: 考虑每个人向他要打的人连边.根据题意,所有点都有且只有一条出边.那么 ...

  9. 【BZOJ】1124: [POI2008]枪战Maf

    题意 \(n(n < 1000000)\)个人,每个人\(i\)指向一个人\(p_i\),如果轮到\(i\)了且他没死,则他会将\(p_i\)打死.求一种顺序,问死的人最少和最多的数目. 分析 ...

随机推荐

  1. cookie记住密码功能

    很多门户网站都提供了记住密码功能,虽然现在的浏览器都已经提供了相应的记住密码功能 效果就是你每次进入登录页面后就不需要再进行用户名和密码的输入: 记住密码功能基本都是使用cookie来进行实现的,因此 ...

  2. DOM 元素节点几何量与滚动几何量

    当在 Web 浏览器中查看 HTML 文档时,DOM 节点被解析,并被渲染成盒模型(如下图),有时我们需要知道一些信息,比如盒模型的大小,盒模型在浏览器中的位置等等,本文我们就来详细了解下元素节点的几 ...

  3. [PGM] I-map和D-separation

    之前在概率图模型对概率图模型做了简要的介绍.此处介绍有向图模型中几个常常提到的概念,之前参考的多为英文资料,本文参考的是<概率图模型-原理与技术的>中译版本.很新的书,纸质很好,翻译没有很 ...

  4. 如何把自己打造成技术圈的 papi 酱

    最近半年,一个叫papi酱的平胸女子连续在微博.朋友圈.创业圈刷屏,当之无愧成了中文互联网的第一大网红.呃,你以为我会巴拉巴拉说一堆网工创业的事?NO,今天想借papi酱的话题跟大家一起聊聊程序员如何 ...

  5. 没有jquery的时候,你看看这个

    vjs var br = (function() { var ua = navigator.userAgent.toLowerCase(); browser = { iPhone: /iphone/. ...

  6. C 语言学习的第 03 课:你的 idea 是怎么变成能够执行的程序的

    在上一篇文章中,我们说到,C 语言系统应该由程序开发环境,C 语言本身和 C 语言的库组成.且同时说了程序开发环境做了“编写”,“预处理”,“编译”和“链接”这几件事情.但是细节并没有一一呈现.不知道 ...

  7. Spring学习进阶(四) Spring JDBC

    Spring JDBC是Spring所提供的持久层技术.主要目的是降低使用JDBC API的门槛,以一种更直接,更简洁的方式使用JDBC API.在Spring JDBC里用户仅需要做哪些比不可少的事 ...

  8. 开发错误记录11:git报错 fatal:open /dev/null or dup failed: No such file or directory

    今天在自己的的电脑上装了git,没成想运行报错: 重装了几次git ,都不行,电脑上没有装github桌面版; 后来在网上查到了方法,反映这是系统的问题: null是比较特殊的系统文件,它实际上是为操 ...

  9. JavaMelody监控SQL

    前言 前面讲过了Javamelody的基本配置,这里简单的介绍下,如何使用Javamelody来监控JDBC以及SQL. 手码不易,转载请注明:xingoo 在网上搜索很多资料,仅有开源社区上的两篇帖 ...

  10. confluence的安装、备份和恢复(wiki)

    还有一种比较不错的wiki工具MediaWiki 安装教程参考 http://pangge.blog.51cto.com/6013757/1560249 我是按照上面的教程搭建的 还有几篇不错的文章 ...