2022 CCPC桂林 L 拓扑+dp+贪心

1 minute read

Published:

题目

已知一个排列某些位置上的数,再给你 m 个限制 (u,v),要求 pu<pv,问能不能求出来一种合法的排列。不合法输出 1

解法

跑两次拓扑排序:

  1. 一次正向,求出每个位置 i 的最小可能值 li
  2. 一次反向,求出每个位置 i 的最大可能值 ri
  3. 得到每个点的可行域 [li,ri]
  4. 用优先队列维护当前最小的右端点进行贪心选择
#include<bits/stdc++.h>
#define ll long long
#define int long long
#define INF 0x3f3f3f3f
#define fi first
#define se second
#define set9 fixed<<setprecision(9)
#define set12 fixed<<setprecision(12)
#define set2 fixed<<setprecision(2)
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define pii pair<int,int>
#define pll pair<long long,long long>
#define db double
#define rep(i, a, b) for(int i=a;i<=b;i++)
#define per(i, a, b) for(int i=a;i>=b;i--)
using namespace std;
const int maxn=2e5+5;
const ll mod=1e9+7;
inline ll read(){ ll f = 1; ll x = 0;char ch = getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch = getchar();}while(ch>='0'&&ch<='9') x = (x<<3) + (x<<1) + ch - '0',  ch = getchar();return x*f; }
inline ll qpow(ll a,ll b,ll MOD=mod){ll res=1;a%=MOD;while(b>0){if(b&1)res=res*a%MOD;a=a*a%MOD;b>>=1;}return res;}
inline ll Inverse(ll x) { return qpow(x,mod-2);}

int n,m;
struct node
{
    int l,r,in,out,id;
    bool operator< (const node &x){return l<x.l;}
}a[maxn];
vector<int>g[maxn],g2[maxn];
int p[maxn],vis[maxn];

void init()
{
    rep(i,1,n) a[i].l=1,a[i].r=n,a[i].in=0,a[i].out=0,a[i].id=i,g[i].clear(),g2[i].clear(),vis[i]=0;
}

void topl()
{
    queue<int>q;
    rep(i,1,n) if(a[i].in==0) q.push(i);
    while(!q.empty())
    {
        int top=q.front();
        q.pop();
        for(auto v:g[top])
        {
            a[v].in--;
            a[v].l=max(a[v].l,a[top].l+1);
            if(a[v].in==0) q.push(v);
        }
    }
}
void topr()
{
    queue<int>q;
    rep(i,1,n) if(a[i].out==0) q.push(i);
    while(!q.empty())
    {
        int top=q.front();
        q.pop();
        for(auto v:g2[top])
        {
            a[v].out--;
            a[v].r=min(a[v].r,a[top].r-1);
            if(a[v].out==0) q.push(v);
        }
    }
}

void solve()
{
    n=read(),m=read();
    init();
    rep(i,1,n)
    {
        p[i]=read();
        if(p[i]>=1) a[i].l=p[i],a[i].r=p[i],vis[p[i]]=1;
    }
    rep(i,1,m)
    {
        int u=read(),v=read();
        a[u].out++;
        a[v].in++;
        g[u].push_back(v);
        g2[v].push_back(u);
    }
    topl();//正向dp求l
    topr();//反向dp求r
    rep(i,1,n)
    {
        if(a[i].l>a[i].r)
        {
            puts("-1");
            return ;
        }
    }
    rep(i,1,n)
    {
        if(a[i].l==a[i].r) vis[a[i].l]=1,p[i]=a[i].l;
    }
    sort(a+1,a+1+n);
    priority_queue<pii,vector<pii>,greater<pii> >q;
    int j=1;
    rep(i,1,n)
    {
        while(j<=n&&a[j].l<=i){ q.push({a[j].r,a[j].id}),j++; }
        if(q.empty())
        {
            puts("-1");
            return;
        }
        auto [val,id]=q.top();
        q.pop();
        if(val<i)
        {
            puts("-1");
            return ;
        }
        p[id]=i;
    }
    rep(i,1,n) printf("%lld ",p[i]);
    puts("");
}


signed main()
{
    int _;_=read();while(_--) solve();
}