传送门:​​点击打开链接​

题意:有n个人,每个人都有学历。然后m个关系,每个关系有u和v,表示u和v是朋友

现在要求,如果是u和v是朋友,那么学历高的人的工资就必须比学历低的人的工资高

如果u和v都是x的朋友,那么对于u和v,那么学历高的人的工资就必须比学历低的人的工资高

说白了就是,通过1条边或者2条边相连的点之间,学历高的工资要更高

问这样去安排工资,那么总工资最低是多少。

思路:因为最多关系中只会相差2条边,所以我们当然会去考虑dp


对于每个节点u,我们去维护Max1和Max2。表示u节点的周围学历比u的学历要低的点中,工资最大值和次大值。

还要顺便维护一个nam,表示工资最大的那个的学历是多少。

首先,我们读入人的学历,按学历从小到大排序,然后从小到大考虑人的工资。

对于点u,假如v是u的相邻节点,那么u的工资会等于max(Max1[v],Max1[u])+1

但是这样写还是不够的,因为如果它周围的最大工资的那个人,实际上学历和它是一样的,那么没必要+1

所以这里我们才维护了次大值,当取最大值的那个nam等于u的工资时,那么我们就只需要用次大值工资去更新了,这样答案会更优。

在计算完u的答案之后,我们还要遍历一遍v,维护下v的Max1和Max2

最后把所有节点的答案累加输出即可

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<bitset>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;

const int MX = 4e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;

int Head[MX], erear;
struct Edge {
int v, nxt;
} E[MX * 2];
void edge_init() {
erear = 0;
memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v) {
E[erear].v = v;
E[erear].nxt = Head[u];
Head[u] = erear++;
}

int ans[MX];
int Max1[MX], Max2[MX], nam[MX];
struct Data {
int id, x;
bool operator<(const Data &P) const {
return x < P.x;
}
} A[MX];

int main() {
int n, m; //FIN;
while(~scanf("%d", &n)) {
edge_init();
memset(Max1, 0, sizeof(Max1));
memset(Max2, 0, sizeof(Max2));
memset(nam, 0, sizeof(nam));

for(int i = 1; i <= n; i++) {
A[i].id = i;
scanf("%d", &A[i].x);
}
sort(A + 1, A + 1 + n);

scanf("%d", &m);
for(int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
edge_add(u, v);
edge_add(v, u);
}

for(int i = 1; i <= n; i++) {
Data tp = A[i];
if(tp.x == nam[tp.id]) ans[tp.id] = Max2[tp.id] + 1;
else ans[tp.id] = Max1[tp.id] + 1;
for(int i = Head[tp.id]; ~i; i = E[i].nxt) {
int v = E[i].v;
if(tp.x == nam[v]) ans[tp.id] = max(ans[tp.id], Max2[v] + 1);
else ans[tp.id] = max(ans[tp.id], Max1[v] + 1);
}

for(int i = Head[tp.id]; ~i; i = E[i].nxt) {
int v = E[i].v;
if(ans[tp.id] > Max1[v]) {
Max2[v] = Max1[v];
Max1[v] = ans[tp.id];
nam[v] = tp.x;
} else if(ans[tp.id] > Max2[v]) {
Max2[v] = ans[tp.id];
}
}
}

LL res = 0;
for(int i = 1; i <= n; i++) {
res += ans[i];
}
printf("%lld\n", res);
}
return 0;
}