当前位置: 代码迷 >> 综合 >> CF B. Berland Army
  详细解决方案

CF B. Berland Army

热度:83   发布时间:2023-10-29 08:24:35.0

前言

做完开了个假的ACM。
想着有队友带,我一个多小时一直在做B
一直有个bug没想到。
然后我就一题没A。
回宿舍的时候想到了。在这里说说做法吧

题意

给你n个数,一开始有确定的,有不确定的
然后有m条限制,表示x比y大
然后所有的数都在1~k之间,且1~k必须至少出现一次

题解

我们考虑拓扑排序
把x比y大的建成边,得到一个图
先正着来
扫出每一个位置上可以填的最大值
先把他都填进去
记为a[x]a[x]
然后这时候1~k的某些数可能没有出现
那么我们就顺序1~k来扫,看看这个数字填了没
考虑我们更改我们现在所填的数字
顺便倒着拓扑,记录一个g[x]g[x],表示我们当前a的填法,这个位置可以填的最小值
当一个数字ii没有出现过的时候,我们考虑哪些点是可以填i的
1. a [ x ] > i
2.g[x]<i2.g[x]<i
当然,要正着拓扑当前入度为0
于是我们可以开两个队列
显然地,如果g已经符合要求,那么我们就要贪心地取a最小的
于是我们可以开两个队列分别记录g达到要求和没达到要求的
达到要求的,就按a排序
另外一个。就按b排序
然后就可以了

CODE:

#include<cstdio>
#include<cstdlib>
#include<queue>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef pair<int,int> PI;
const int N=200005;
int n,m,k;
int a[N];
bool o[N];//是不是一开始有有数了 
struct qq
{int x,y,last;
}e[N];int num,last[N];
qq E[N];int Last[N];
int d[N],D[N];
void init (int x,int y)
{num++;d[y]++;e[num].x=x;e[num].y=y;e[num].last=last[x];last[x]=num;swap(x,y);D[y]++;E[num].x=x;E[num].y=y;E[num].last=Last[x];Last[x]=num;
}
priority_queue<PI,vector<PI>,greater<PI> >Q,Q1 ;
int tt[N];
int g[N];
void solve1 ()
{
/* for (int i=1;i<=n;i++) printf("%d ",a[i]);printf("\n");*/memset(g,0,sizeof(g));for (int u=1;u<=n;u++){if (D[u]==0){Q.push(make_pair(a[u],u));g[u]=1;}tt[a[u]]++;}for (int u=1;u<=k;u++)if (tt[u]==0)//如果这个颜色不存在 {while (!Q1.empty()){int x=Q1.top().first,y=Q1.top().second;if (x>u) break;Q1.pop();Q.push(make_pair(a[y],y));}while (!Q.empty()){int x=Q.top().first,xx=Q.top().second;Q.pop();if (x<u||o[xx]) {for (int i=Last[xx];i!=-1;i=E[i].last){int y=E[i].y;D[y]--;g[y]=max(g[y],a[xx]+1);if (D[y]==0)Q1.push(make_pair(g[y],y));}continue;}else{tt[a[xx]]--;a[xx]=u;tt[u]++;for (int i=Last[xx];i!=-1;i=E[i].last){int y=E[i].y;D[y]--;g[y]=max(g[y],a[xx]+1);if (D[y]==0)Q1.push(make_pair(g[y],y));}break;}}/* for (int i=1;i<=n;i++) printf("%d ",a[i]);printf("\n");system("pause");*/if (tt[u]==0) {
   printf("-1");return ;}}for (int u=1;u<=n;u++) printf("%d ",a[u]);
}
queue<int> q;
void solve ()
{int tot=0;for (int u=1;u<=n;u++) if (d[u]==0) {q.push(u);if (o[u]==false) a[u]=k;}
/* for (int u=1;u<=n;u++) printf("%d ",a[u]);printf("\n");*/while (!q.empty()){tot++;int x=q.front();for (int u=last[x];u!=-1;u=e[u].last){int y=e[u].y;if (o[y]){if (a[y]>=a[x]){printf("-1");return ;}}else    a[y]=min(a[y],a[x]-1);d[y]--;if (d[y]==0)    q.push(y);}//printf("%d\n",x);q.pop();/**/}for (int u=1;u<=n;u++)if (a[u]<=0){printf("-1");return ;}if (tot!=n){printf("-1");return ;}/*for (int u=1;u<=n;u++) printf("%d ",a[u]);printf("\n");*/solve1();
}
int main()
{num=0;memset(last,-1,sizeof(last));memset(Last,-1,sizeof(Last));scanf("%d%d%d",&n,&m,&k);for (int u=1;u<=n;u++) {scanf("%d",&a[u]);if (a[u]==0) {a[u]=k+1;o[u]=false;}else o[u]=true;}for (int u=1;u<=m;u++){int x,y;scanf("%d%d",&x,&y);init(x,y);}solve();return 0;
}