F. Mentors
description:
给出n个数代表n个人的技能值,之后给出一组关系代表两两人之间有矛盾,问最后对于每个人来说,有多少人和他没矛盾且技能值严格小于他。
input:
第一行n和k分别代表人数和有矛盾的对数。
之后k行每行两个数,代表两个人有矛盾。
output:
从第一个人到第n个人,依次输出符合条件的人数。
analysis:
这一题有两个条件:没矛盾 和 技能值小于当前考虑的人。
如果先考虑第一个条件,就会想到图论上去,在意个图中找出互相不连接,且权值小于当前节点的点的个数。然而,这里用图论还是不合适,因为这里面的关系没有传递性,只是两两之间的关系。先考虑第一个条件很不自然。
换一个角度,先考虑第二个条件,那么就只要对技能值排序,就可以直接根据序号找出有多少人的技能值小于当前的人。剩下的是把有矛盾的从其中去掉,可以通过一个slack数组记录和u矛盾的点中技能值比它小的点的个数,这可以在输入u v矛盾对时直接更新slack.
if(a[u].first>a[v].first)slack[u]++; else if(a[v].first>a[u].first)slack[v]++;
最后在对每个点计算答案即可,由于要求严格小于,所以要用lower_bound找出与当前点相等的最小下标,然后减去(slack+1)就是答案了。具体看代码。
代码:
#include<iostream> #include<string> #include<cstring> #include<vector> #include<stack> #include<algorithm> #include<map> #include<set> #include<queue> #include<sstream> #include<cmath> #include<iterator> #include<bitset> #include<stdio.h> using namespace std; #define _for(i,a,b) for(int i=(a);i<(b);++i) #define _rep(i,a,b) for(int i=(a);i<=(b);++i) typedef long long LL; LL readint() { LL x; scanf("%lld",&x); return x; } const int INF = 1 << 30; const int maxn = 200005; int n,m; pair<int,int> a[maxn]; int slack[maxn]; int ans[maxn]; int num[maxn]; int main() { // freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin); // freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout); while(~scanf("%d%d",&n,&m)){ memset(slack,0,sizeof(slack)); for(int i=1;i<=n;++i){scanf("%d",&a[i].first);a[i].second=i;} while(m--){ int u,v;scanf("%d%d",&u,&v); if(a[u].first>a[v].first)slack[u]++; //计算slack else if(a[v].first>a[u].first)slack[v]++; } sort(a+1,a+1+n); for(int i=1;i<=n;++i)num[i]=a[i].first; for(int i=1;i<=n;++i){ int id=a[i].second; ans[id]=(lower_bound(num+1,num+1+n,a[i].first)-num)-slack[id]-1; //计算答案 } for(int i=1;i<=n;++i)printf("%d ",ans[i]); printf("\n"); } return 0; }