1. 程式人生 > >CF #481 (div3)F

CF #481 (div3)F

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]++;elseif(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>usingnamespace 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)typedeflonglong LL
; LL readint(){ LL x; scanf("%lld",&x);return x;}constint INF =1<<30;constint 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 elseif(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");}return0;}