LOJ6807 「THUPC 2022 初赛」最小公倍树

参考代码

// problem: LOJ6807
#include <bits/stdc++.h>
using namespace std;

#define pb push_back
#define mk make_pair
#define lob lower_bound
#define upb upper_bound
#define fi first
#define se second
#define SZ(x) ((int)(x).size())

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

template<typename T> inline void ckmax(T& x, T y) { x = (y > x ? y : x); }
template<typename T> inline void ckmin(T& x, T y) { x = (y < x ? y : x); }

const int MAXN = 1e5 + 1;

int L, R;
int f[MAXN + 5], g[MAXN + 5];

int fa[MAXN + 5], sz[MAXN + 5];
int get_fa(int u) {
return (fa[u] == u) ? u : (fa[u] = get_fa(fa[u]));
}
void unite(int u, int v) {
int uu = get_fa(u);
int vv = get_fa(v);
if (uu != vv) {
if (sz[uu] > sz[vv])
swap(uu, vv);
fa[uu] = vv;
sz[vv] += sz[uu];
}
}

int main() {
cin >> L >> R;
priority_queue<pair<ll, int> > que;
for (int i = 1; i <= R - L; ++i) {
f[i] = ((L - 1) / i + 1) * i; // >= L 的第一个 i 的倍数
if (f[i] + i <= R) {
g[i] = f[i] + i;
que.push(mk(-(ll)f[i] / i * g[i], i));
}
}
for (int i = 1; i <= R - L + 1; ++i) {
fa[i] = i;
sz[i] = 1;
}
ll ans = 0;
for (int i = 1; i <= R - L; ++i) {
pair<ll, int> t = que.top();
que.pop();
while (get_fa(f[t.se] - L + 1) == get_fa(g[t.se] - L + 1)) {
g[t.se] += t.se;
if (g[t.se] <= R) {
que.push(mk(-(ll)f[t.se] / t.se * g[t.se], t.se));
}
t = que.top();
que.pop();
}
ans -= t.fi; // 根据默认大根堆的特点，t.fi 是负数
unite(f[t.se] - L + 1, g[t.se] - L + 1);
g[t.se] += t.se;
if (g[t.se] <= R) {
que.push(mk(-(ll)f[t.se] / t.se * g[t.se], t.se));
}
// cerr << "add " << f[t.se] << " " << g[t.se] << endl;
}
cout << ans << endl;
return 0;
}
posted @ 2022-04-10 18:15  duyiblue  阅读(244)  评论(2编辑  收藏  举报