2020 ccpc 网络赛 1004 Chess Class
题意:
当时开都没开,之后补题的时候发现似乎应该是个银牌题目?
我们从先手的角度看,他一定是想要让别的点尽可能的向权值大的点靠拢,如果那个点属于X,那么这个点最终向谁连边是由他定的,他一定会连向收益最大的那条路径。如果这个点不属于X,那么这个点最终向一条路径连边一定是其他边走出去都比他大。
具体哪条路径更大我们在原图很难看出,我们不妨在反图上进行操作。
因为最终答案是路径上最大权值最大的点,我们将点按照权值从大到小进行考虑,因为当一个路径经过权值最大的点了之后,它之后怎么走都不会影像答案。
现在,我们先考虑如何找到ans为最大权值的点。我们设这个点为a。
显然,他自己是满足条件的。接着,我们很容易看出,如果b属于X,反图中a向b连边,那么,b保留边的时候一定会保留向a的边,把其他边删掉,所以b的ans和a一样。如果b不属于X,反图中a向b连边,那么,只要a->b不是b唯一的入边,那么b选择不保留这条边一定不劣,所以,b和a答案相同当且仅当这是b唯一的入边。
不难发现,我们从b向外继续扩充,新的得到的点依旧满足答案和a一样,所以我们通过bfs就可以知道答案为最大权的点。之后,我们再枚举权值第二大,第三大……最小的点,像上面一样依次bfs,就可以得到所有点的答案。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<queue> 7 #include<cmath> 8 #define N 500005 9 using namespace std; 10 int T,n,m,R,B; 11 int bj[N]; 12 int W[N]; 13 int a[N],zz,rd[N]; 14 struct ro{ 15 int to,next; 16 }road[N]; 17 void build(int x,int y) 18 { 19 zz++; 20 road[zz].to=y; 21 road[zz].next=a[x]; 22 a[x]=zz; 23 } 24 int A[N]; 25 bool cmp(int x,int y) 26 { 27 return W[x]>W[y]; 28 } 29 queue<int> q1; 30 int ans[N]; 31 int cnt; 32 void bfs(int X) 33 { 34 while(!q1.empty()) 35 { 36 int x=q1.front();q1.pop(); 37 for(int i=a[x];i;i=road[i].next) 38 { 39 int y=road[i].to; 40 if(ans[y]!=-1)continue; 41 if(bj[y]) 42 { 43 ans[y]=X; 44 if(y!=x) q1.push(y); 45 } 46 else 47 { 48 rd[y]--; 49 if(!rd[y]) 50 { 51 ans[y]=X; 52 if(y!=x) q1.push(y); 53 } 54 } 55 } 56 } 57 } 58 int main() 59 { 60 scanf("%d",&T); 61 while(T--) 62 { 63 cnt++; 64 scanf("%d%d%d%d",&n,&m,&R,&B); 65 memset(bj,0,sizeof(bj)); 66 zz=0; 67 memset(a,0,sizeof(a)); 68 memset(rd,0,sizeof(rd)); 69 memset(ans,-1,sizeof(ans)); 70 for(int i=1;i<=B;i++) 71 { 72 int x; 73 scanf("%d",&x); 74 bj[x]=1; 75 } 76 for(int i=1;i<=n;i++) 77 { 78 scanf("%d",&W[i]); 79 A[i]=i; 80 } 81 for(int i=1;i<=m;i++) 82 { 83 int x,y; 84 scanf("%d%d",&x,&y); 85 build(y,x); 86 rd[x]++; 87 } 88 sort(A+1,A+n+1,cmp); 89 for(int i=1;i<=n;i++) 90 { 91 int j=i; 92 for(;j<=n;j++) 93 { 94 if(W[A[j]]!=W[A[i]]) 95 { 96 j--; 97 break; 98 } 99 } 100 for(int k=i;k<=j;k++) 101 { 102 if(ans[A[k]]==-1) 103 { 104 q1.push(A[k]); 105 ans[A[k]]=W[A[i]]; 106 } 107 108 } 109 bfs(W[A[i]]); 110 i=j; 111 } 112 printf("Case #%d:\n",cnt); 113 for(int i=1;i<n;i++) printf("%d ",ans[i]); 114 printf("%d\n",ans[n]); 115 } 116 return 0; 117 }