[POI2008]枪战Maf

[POI2008]枪战Maf

题目

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

INPUT

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

OUTPUT

你要求最后死亡数目的最小和最大可能

SAMPLE

INPUT

8

2 3 2 2 6 7 8 5

OUTPUT

3 5

解题报告

考试时候打出了tarjan,然而不会用= =

正解:

tarjan

我们分连通块来考虑

首先自杀的一定死

一个环上的,最多死 点数-1 个(一个人开始开枪,然后被杀,最后只剩一个),最少死一半(假如少于一半,那么必然有至少一条直接相连的边没有被砍,必然还会死人)

一个环加上内向树,最多死 点数-入度为0的个数

最少如何处理呢?

入度为0的死不了(没人打他)

将他们推入队列,他们的目标一定死,那就让他们死,然后他们的目标入度减1,看看是否变为入度为0,依次处理

最后剩下的一定是一堆环

然后就可以在欢声笑语中打出GG

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<queue>
  6 using namespace std;
  7 inline int read(){
  8     int sum(0);
  9     char ch(getchar());
 10     for(;ch<'0'||ch>'9';ch=getchar());
 11     for(;ch>='0'&&ch<='9';sum=sum*10+(ch^48),ch=getchar());
 12     return sum;
 13 }
 14 int n;
 15 struct edge{
 16     int s,e,n;
 17 }a[1000001];
 18 int pre[1000001],tot;
 19 inline void insert(int s,int e){
 20     a[++tot].s=s;
 21     a[tot].e=e;
 22     a[tot].n=pre[s];
 23     pre[s]=tot;
 24 }
 25 inline int my_max(int a,int b){
 26     return a>b?a:b;
 27 }
 28 inline int my_min(int a,int b){
 29     return a<b?a:b;
 30 }
 31 struct node{
 32     int id;
 33 }hh[1000001];
 34 bool die[1000001];
 35 int target[1000001];
 36 int ans_min(0),ans_max(0);
 37 int in[1000001];
 38 int low[1000001],dfn[1000001],zhan[1000001],bl[1000001],size[1000001];
 39 int cnt,top,qlt;
 40 bool vis[1000001];
 41 int cl[1000001];
 42 inline void tarjan(int u){
 43     dfn[u]=low[u]=++cnt;
 44     zhan[++top]=u;
 45     vis[u]=1;
 46     for(int i=pre[u];i!=-1;i=a[i].n){
 47         int e(a[i].e);
 48         if(!dfn[e]){
 49             tarjan(e);
 50             low[u]=my_min(low[u],low[e]);
 51         }
 52         else
 53             if(vis[e])
 54                 low[u]=my_min(low[u],dfn[e]);
 55     }
 56     if(low[u]==dfn[u]){
 57         qlt++;
 58         while(1){
 59             int tmp(zhan[top--]);
 60             bl[tmp]=qlt;
 61             vis[tmp]=0;
 62             size[qlt]++;
 63             if(tmp==u)
 64                 break;
 65         }
 66     }
 67 }
 68 inline bool cmp(node a,node b){
 69     if(cl[bl[a.id]]==cl[bl[b.id]])
 70         return in[a.id]<in[b.id];
 71     return cl[bl[a.id]]<cl[bl[b.id]];
 72 }
 73 queue<int>q;
 74 int now(0x7fffffff),inf(0x7fffffff),fir;
 75 int main(){
 76     memset(pre,-1,sizeof(pre));
 77     n=read();
 78     for(int i=1;i<=n;i++){
 79         hh[i].id=i;
 80         target[i]=read();
 81         if(target[i]==i){
 82             die[i]=1;
 83             bl[i]=++qlt;
 84             cl[qlt]=0;
 85             size[qlt]=1;
 86             ans_max++,ans_min++;
 87         }
 88     }
 89     for(int i=1;i<=n;i++){
 90         if(!die[i]&&!die[target[i]])
 91             insert(i,target[i]),in[target[i]]++;
 92     }
 93     for(int i=1;i<=n;i++)
 94         if(!dfn[i]&&!die[i])
 95             tarjan(i);
 96     for(int i=1;i<=tot;i++){
 97         int s(a[i].s),e(a[i].e);
 98         s=bl[s],e=bl[e];
 99         if(s!=e)
100             cl[s]=cl[e]=1;
101     }
102     for(int i=1;i<=qlt;i++){
103         if(cl[i]==0&&size[i]>1){
104             ans_max+=size[i]-1;
105             ans_min+=(size[i]+1)>>1;
106         }
107     }
108     sort(hh+1,hh+1+n,cmp);
109     for(int i=1;i<=n;i++){
110         int tmp(hh[i].id);
111         if(cl[bl[tmp]]==1&&!in[tmp]){
112             now=my_min(now,i);
113             continue;
114         }
115         if(cl[bl[tmp]]==1&&in[tmp]){
116             fir=i;
117             break;
118         }
119     }
120     if(now!=inf){
121         ans_max+=n-fir+1;
122         for(int i=now;i<fir;i++)
123             q.push(hh[i].id);
124         while(!q.empty()){
125             int k(q.front());
126             cl[bl[k]]=0;
127             q.pop();
128             int tar(target[k]);
129             if(!die[tar]){
130                 die[tar]=1;
131                 cl[bl[tar]]=0;
132                 ans_min++;
133                 int kk(target[tar]);
134                 in[kk]--;
135                 if(!die[kk]&&!in[kk])
136                     q.push(kk);
137             }
138         }
139     }
140     for(int i=1;i<=cnt;i++)
141         if(cl[i])
142             ans_min+=(size[i]+1)>>1;
143     printf("%d %d",ans_min,ans_max);
144 }
View Code

 

转载于:https://www.cnblogs.com/hzoi-mafia/p/7277750.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值