传送门:点击打开链接
题意:有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; }