[题解] [JSOI2010] 排名

题面

题解

题目很简单, 用优先队列维护拓扑序即可
但是他要我们求的东西比较诡异, 导致贪心的策略会不同
对于第一问, 我们一般的思路是直接维护正的拓扑序, 每次选最小的更新
但这样不一定是最优的, 因为选择了当前最小的可能使得更小的拓扑序排在后面, 这样字典序就不一定是最小的了
所以我们维护反的拓扑序, 每次选最大的更新
第二问可以直接用大根堆维护正的拓扑序就行了

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
const int N = 200005; 
using namespace std;

int n, a[N], deg[N], in[N], ans[N], head[N], cnt;
struct edge { int to, nxt; } e[N];
priority_queue<int> q; 

template < typename T >
inline T read()
{
    T x = 0, w = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * w; 
}

inline void adde(int u, int v) { e[++cnt] = (edge) { v, head[u] }, head[u] = cnt; }

int main()
{
    n = read <int> ();
    for(int i = 1; i <= n; i++)
    {
	a[i] = read <int> ();
	if(a[i]) adde(a[i], i), deg[a[i]]++, in[i]++; 
    }
    cnt = n; 
    for(int i = 1; i <= n; i++)
	if(!deg[i]) q.push(i);
    while(!q.empty())
    {
	int u = q.top(); q.pop();  
	ans[u] = cnt--;
	if(!(--deg[a[u]])) q.push(a[u]); 
    }
    for(int i = 1; i <= n; i++)
	printf("%d%c", ans[i], i == n ? '
' : ' '); 
    cnt = 0;
    for(int i = 1; i <= n; i++)
	if(!in[i]) q.push(i); 
    while(!q.empty())
    {
	int u = q.top(); q.pop();
	ans[u] = ++cnt; 
	for(int v, i = head[u]; i; i = e[i].nxt)
	{
	    v = e[i].to;
	    q.push(v); 
	}
    }
    for(int i = 1; i <= n; i++)
	printf("%d%c", ans[i], i == n ? '
' : ' '); 
    return 0; 
}
原文地址:https://www.cnblogs.com/ztlztl/p/12258659.html