1463E.Plan of Lectures(缩点+拓扑排序)

题意

给出一棵树,询问这颗树的一个拓扑序,使得给出的k个点对在拓扑序里相邻。

题解

用缩点处理每个点对,然后对缩点后的图做拓扑排序即可。

需要保证的是k个点对形成的图是若干条链,这里的判断写的有点乱。

//给出一个有向图
//求一个拓扑序
//同时k条边需要满足相邻访问

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+100;
vector<int> g[maxn];
int n,k;
int p[maxn];
int nxt[maxn],in[maxn],pos[maxn];
int dfn[maxn],tot,inDegree[maxn];
void topOrder () {
    queue<int> q;
    for (int i=1;i<=n;i++) {
        if (pos[i]==i&&inDegree[i]==0) {
            q.push(i); 
        }
    }
    while (q.size()) {
        int u=q.front();
        q.pop();
        int tt=u;
        while (tt) {
            dfn[++tot]=tt;
            tt=nxt[tt];
        }
        for (int v:g[u]) if (--inDegree[v]==0) {
            q.push(v);
        }
    }
}
int h[maxn];
int main () {
    int rt;
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++) scanf("%d",p+i);
    for (int i=1;i<=k;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        if (nxt[x]) {
            return printf("0"),0;
        }
        if (in[y]) {
            return printf("0"),0;
        }
        nxt[x]=y;
        in[y]++;
    }
    for (int i=1;i<=n;i++) {
        if (pos[i]) continue;
        if (in[i]) continue;
        int u=i;
        h[u]=1;
        while (u) {
            pos[u]=i;
            if (nxt[u]&&h[nxt[u]]) return printf("0"),0;
            if (nxt[u]) h[nxt[u]]=h[u]+1;
            u=nxt[u];
        }
    }
    //for (int i=1;i<=n;i++) printf("%d ",pos[i]);
    //printf("
");
    for (int i=1;i<=n;i++) {
        if (!p[i])
            rt=i;
        else if (pos[p[i]]==pos[i]) {
            if (h[i]<h[p[i]]) return printf("0"),0;
            continue;
        }
        else
            g[pos[p[i]]].push_back(pos[i]),inDegree[pos[i]]++;
    }
    //for (int i=1;i<=n;i++) if (pos[i]==i) printf("%d %d
",i,inDegree[i]);
    topOrder();
    if (tot<n) return printf("0"),0;
    for (int i=1;i<=n;i++) printf("%d ",dfn[i]);
} 
原文地址:https://www.cnblogs.com/zhanglichen/p/14340212.html