原题传送门
肯定是让你一排一排的考虑
那就一排一排的考虑
暴力做法就是暴力 k r u s k a l kruskal kruskal,那么怎么把一整排看成一条边?这样就可以满分了
根据 k r u s k a l kruskal kruskal我们可以知道,只要每次选取最小的边且还未联通就是最优的
那么就直接一排一排的搞,每次加进来一排值最小的,但是要减去多余的部分(这部分若加入,那么会形成环)
- 第一次出现横行或列行,全部加
- 若不是第一次,则看与自己垂直的有几排,只有一排或没有,不会形成环,全加;否则有 x ( x > 1 ) x(x>1) x(x>1)排,则要减去 x − 1 x-1 x−1条边
开ll
Code:
#include <bits/stdc++.h>
#define maxn 300010
#define LL long long
using namespace std;
int n, m;
struct node{LL x, opt;
}a[maxn << 1];
LL cnt[2];inline int read(){int s = 0, w = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) +(c ^ 48);return s * w;
}bool cmp(node x, node y){ return x.x < y.x; }int main(){n = read(), m = read();for (int i = 1; i <= n; ++i) a[i] = (node){read(), 0};for (int i = n + 1; i <= n + m; ++i) a[i] = (node){read(), 1};sort(a + 1, a + 1 + n + m, cmp);LL ans = 0;for (int i = 1; i <= n + m; ++i){LL num = a[i].opt ? n : m;if (!cnt[a[i].opt]) ans += (num - 1) * a[i].x;else ans += (num - max(1LL, cnt[a[i].opt ^ 1])) * a[i].x;++cnt[a[i].opt];}printf("%lld\n", ans);return 0;
}