题目戳这:http://www.lydsy.com/JudgeOnline/upload/5026.pdf
思路&&分析
其实..第一问有O(n)的做法而且很容易想到,但我就是第一第二问都写了优先队列来弄答案..第一问我是对于所有的i,如果a[i]不是0,那么将i向a[i]连一条边,然后对于没有入度的点开始拓扑,用一个大根堆从排名最低的开始贪心就行了。第二问我是a[i]向i连一条边,然后用大根堆从排名为1的开始贪心,然后对于遍历到的每个点,将他所有可达的点都push进来就行了。
Code
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const int maxn=200020;
int n,ans[maxn],d[maxn],rk;
priority_queue<int>q,p;
vector<int>G[maxn],F[maxn];
int main() {
read(n);
for(int i=1,x;i<=n;i++) {
read(x);
if(!x)
q.push(i);
G[x].push_back(i);
F[i].push_back(x);
d[x]++;
}
rk=n;
for(int i=1;i<=n;i++)
if(!d[i])
p.push(i);
while(!p.empty()) {
int u=p.top();
p.pop();
ans[u]=rk--;
for(unsigned i=0;i<F[u].size();i++)
if(!--d[F[u][i]])
p.push(F[u][i]);
}
for(int i=1;i<=n;i++)
printf("%d%c",ans[i],i<n?' ':'\n');
rk=1;
while(!q.empty()) {
int u=q.top();
q.pop();
ans[u]=rk++;
for(unsigned i=0;i<G[u].size();i++)
q.push(G[u][i]);
}
for(int i=1;i<=n;i++)
printf("%d%c",ans[i],i<n?' ':'\n');
}
花絮
这题我原来第一问是从小到大开始拓扑第二问是从大到小开始拓扑的,然后发现WA了,就把第一问改成了从大到小开始拓扑,然后进行对拍,之后发现拍到一组数据是后面的更优,于是我就又交了一遍,发现还是wa。于是我就把第二问改成了从小到大,又对拍了一遍,发现还是后面的更优,于是就又交了一遍,就过了23333..