这题主要是优先队列的用法,我们需要让已经入队的元素按照小的来出队,这时候普通的队列已经不满足了,我们需要用到优先队列,由于优先队列的实现其实就是堆的建立,入队出队操作的时间复杂度是log,比一般队列慢很多,而且因为时stl的缘故里面有很多不必要的,但对于这题来说够用了,优先队列实现起来和动态开点线段树差不多,就增删改,查询区间最小进行删除即可,说起来其实就是动态开点线段树的查询区间第k小或者第k大的操作
优先队列默认优先级大的先出队:
priority_queue<int> q;
优先队列默认优先级小的先出队:
priority_queue<int, vector<int>, greater<int> > q;
利用 优先队列 实现本题代码:
#include <cstdio>
#include <algorithm>
#include <vector>
#include <iostream>
#include <map>
#include <queue>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
using namespace std;
#define inf 1 << 28
const int maxn = 1e5 + 5;
typedef long long ll;
struct node
{
int v, nex;
} edge[maxn];
int cnt, head[maxn], p[maxn];
void add(int u, int v)
{
edge[cnt].v = v;
edge[cnt].nex = head[u], head[u] = cnt++;
}
int in[maxn], n, m;
void solv()
{
priority_queue<int, vector<int>, greater<int> > q;
int ans = 0;
for (int i = 1; i <= n; i++)
{
if (!in[i])
q.push(i);
}
while (!q.empty())
{
int u = q.top();
p[ans++]=u;
q.pop();
for (int i = head[u]; ~i; i = edge[i].nex)
{
int v = edge[i].v;
in[v]--;
if (!in[v])
{
q.push(v);
}
}
}
for(int i=0;i<ans;i++)
{
if(i!=ans-1)
cout<<p[i]<<' ';
else
{
cout<<p[i]<<endl;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
while (cin >> n >> m)
{
memset(head, -1, sizeof(head));
memset(edge, 0, sizeof(edge));
cnt = 0;
for (int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
add(u, v), in[v]++;
}
solv();
}
}
动态开点模拟优先队列:
参考代码:
#include <cstdio>
#include <algorithm>
#include <vector>
#include <iostream>
#include <map>
#include <queue>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
using namespace std;
const int inf = 1e3+5;
const int maxn = 1e3+5;
typedef long long ll;
struct node
{
int v, nex;
} edge[maxn];
int cnt, cnx, head[maxn], p[maxn];
int k;
struct vain
{
int ls, rs, sum;
} tr[maxn * 50];
void inser(int &k, int L, int R, int pos, int w)
{
if (!k)
k = ++cnx;
tr[k].sum += w;
if (L == R)
return;
int mid = L + R >> 1;
if (mid >= pos)
inser(tr[k].ls, L, mid, pos, w);
else
inser(tr[k].rs, mid + 1, R, pos, w);
}
int ask(int k, int L, int R, int s)
{
if (L == R)
return L;
int mid = L + R >> 1;
int sum = tr[tr[k].ls].sum;
if (sum >= s)
return ask(tr[k].ls, L, mid, s);
else
return ask(tr[k].rs, mid + 1, R, s - sum);
}
void pus(int x)
{
inser(k, 1, inf, x, 1);
}
int tp()
{
return ask(k, 1, inf, 1);
}
void de()
{
int x = tp();
inser(k, 1, inf, x, -1);
}
int judge()
{
return tr[1].sum;
}
void add(int u, int v)
{
edge[cnt].v = v;
edge[cnt].nex = head[u], head[u] = cnt++;
}
int in[maxn], n, m;
void solv()
{
int ans = 0;
for (int i = 1; i <= n; i++)
{
if (!in[i])
pus(i);
}
while (judge())
{
int u = tp();
p[ans++] = u;
de();
for (int i = head[u]; ~i; i = edge[i].nex)
{
int v = edge[i].v;
in[v]--;
if (!in[v])
{
pus(v);
}
}
}
for (int i = 0; i < ans; i++)
{
if (i != ans - 1)
cout << p[i] << ' ';
else
{
cout << p[i] << endl;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
while (cin >> n >> m)
{
memset(head, -1, sizeof(head));
memset(edge, 0, sizeof(edge));
memset(tr,0,sizeof(tr));
cnt = 0,cnx=0,k=0;
for (int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
add(u, v), in[v]++;
}
solv();
}
}