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 }
View Code

 

posted @ 2020-09-26 10:03  Hzoi_joker  阅读(273)  评论(0编辑  收藏  举报