[POI2008]MAF-Mafia

Description

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

Input

输入n人数<1000000 每个人的aim

 

Solution

其实就是一个基环树森林

显然可以把每个基环树分开,然后分情况讨论。

环:死最多:len-1,死最少:[len/2]上取整

自环:最多最少都是1

树:死最多:只剩下叶子。死最少:叶子不会死,然后父亲一定死,就贪心地让父亲就别打死爷爷。这样一定不会更劣。大概就是隔一层打一层

基环树:死最多:只剩下叶子。死最少:先把每个子树按照树的打法打完,然后基环可能会变成若干个链,每个链都是:len/2下取整。剩环的话,那么和环(或者自环)一样。

 

树和基环树的叶子往上打就是拓扑排序。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000000+5;
int n;
struct node{
    int nxt,to;
}e[2*N];
int hd[N],cnt=1;
int du[N];//you xiang
int huan;//len of huan
bool on[N];//on the huan
bool vis[N];
bool die[N];
bool go[N];
bool has[N];
int to[N]; 
int mxans,mians;
void add(int x,int y){
    e[++cnt].nxt=hd[x];
    e[cnt].to=y;
    hd[x]=cnt;
}
bool fl;
int sta[N],top;
vector<int>mem;
int in[N];//in the sta
void dfs(int x,int in_edge){
//    cout<<" dfs "<<x<<" "<<endl;
    sta[++top]=x;
    vis[x]=1;in[x]=1;
    mem.push_back(x);
    for(int i=hd[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(i==(in_edge^1)) continue;
        if(vis[y]){
            if(in[y]&&!fl){
            //    cout<<" fin "<<y<<endl;
                fl=true;
                int z;//=sta[top];
                do{
                    z=sta[top];
                    on[z]=1;in[z]=0;
                    huan++;
                    top--;
                }while(z!=y);
            }
        }
        else dfs(y,i);
    }
    if(sta[top]==x) in[x]=0,top--;
}
int q[N],l,r;
int len;//len of lian
void wrk(int x,int pre){//dfs on the huan
    go[x]=1;
    //cout<<x<<" "<<pre<<endl;
    for(int i=hd[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y==pre) continue;
        if(go[y]) continue;
        if(on[y]){
            //cout<<" y "<<y<<endl;
            if(die[y]){
                mians+=len/2;len=0;
            }else len++;
            wrk(y,x);
        }    
    }
}
void topo(){
    len=0;
    l=1,r=0;
    //cout<<" huan "<<huan<<endl;
    //cout<<" mem "<<mem.size()<<endl;
    ///cout<<mians<<endl;
    for(int i=0;i<mem.size();i++){
        int id=mem[i];
        //cout<<id<<" "<<on[id]<<" "<<in[id]<<endl;
        if(du[id]==0) q[++r]=id,has[id]=1;
    }    
    if(huan==0||huan>1) mxans+=mem.size()-max(r,1);
    else mxans+=mem.size()-r;
    bool kil=false;
    int st;
    while(l<=r){
        int x=q[l++];
        //cout<<" x "<<x<<endl;
        //if(has[to[x]]) continue;
        if(!die[x]){
            if(!die[to[x]]) mians++,die[to[x]]=1;
            if(on[to[x]])kil=1,st=to[x];
        }
        du[to[x]]--;
        if(du[to[x]]==0){
            q[++r]=to[x];
        }
    }
    if(kil){
        //cout<<" kil "<<st<<endl;
        //cout<<mians<<endl;
        wrk(st,0);
        //cout<<" len "<<len<<endl;
        mians+=len/2;
    }
    else{
        mians+=huan-(huan/2);
    }
}

int main(){
    scanf("%d",&n);int y;
    for(int i=1;i<=n;i++){
        scanf("%d",&y);to[i]=y;
        add(i,y);add(y,i);du[y]++;
    }
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            //cout<<" another "<<i<<endl;
            fl=false;
            huan=0;
            mem.clear();
            dfs(i,0);
            topo();
            //cout<<" mians "<<mians<<" mxans "<<mxans<<endl;
        }
    }
    cout<<mians<<" "<<mxans<<endl;
    return 0;
}

/*
   Author: *Miracle*
   Date: 2018/10/14 19:28:35
*/

 

posted @ 2018-10-16 17:11  *Miracle*  阅读(332)  评论(0编辑  收藏  举报