[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 }