预处理维护出每个时刻的最大生成树, 就LCT维护就可以了。
#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0); using namespace std; const int N = 3e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 998244353; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T &a, S b) {a += b; if(a >= mod) a -= mod;} template<class T, class S> inline void sub(T &a, S b) {a -= b; if(a < 0) a += mod;} template<class T, class S> inline bool chkmax(T &a, S b) {return a < b ? a = b, true : false;} template<class T, class S> inline bool chkmin(T &a, S b) {return a > b ? a = b, true : false;} mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); int n; LL ans[N]; LL now; int tot; int U[N], V[N]; vector<int> fac[N]; struct LCT { #define l(x) (ch[x][0]) #define r(x) (ch[x][1]) int fa[N], ch[N][2], rev[N], sz[N], q[N]; PII w[N], mn[N]; void init(int n) { for(int i = 0; i <= n; i++) { fa[i] = rev[i] = 0; sz[i] = 1; mn[i] = w[i] = mk(1000000, i); ch[i][0] = ch[i][1] = 0; } tot = n + 1; } inline bool isroot(int x) { return l(fa[x]) != x && r(fa[x]) != x; } inline void pull(int x) { sz[x] = sz[l(x)] + sz[r(x)] + 1; mn[x] = w[x]; chkmin(mn[x], mn[l(x)]); chkmin(mn[x], mn[r(x)]); } inline void push(int x) { if(rev[x]) { rev[x] = 0; swap(l(x), r(x)); rev[l(x)] ^= 1; rev[r(x)] ^= 1; } } inline void rot(int x) { int y = fa[x], z = fa[y], l, r; if(ch[y][0] == x) l = 0, r = l ^ 1; else l = 1, r = l ^ 1; if(!isroot(y)) { if(l(z) == y) l(z) = x; else r(z) = x; } fa[x] = z; fa[y] = x; fa[ch[x][r]]=y; ch[y][l] = ch[x][r]; ch[x][r] = y; pull(y); pull(x); } inline void splay(int x) { int top = 1; q[top] = x; for(int i = x; !isroot(i); i = fa[i]) q[++top] = fa[i]; for(int i = top; i; i--) push(q[i]); while(!isroot(x)) { int y = fa[x], z = fa[y]; if(!isroot(y)) { if((l(y) == x) ^ (l(z) == y)) rot(x); else rot(y); } rot(x); } } inline void access(int x) { for(int y = 0; x; y = x, x = fa[x]) { splay(x); r(x) = y; pull(x); } } inline void makeroot(int x) { access(x); splay(x); rev[x] ^= 1; } inline int findroot(int x) { access(x); splay(x); while(l(x)) x = l(x); return x; } inline void split(int x, int y) { makeroot(x); access(y); splay(y); } inline void link(int x, int y) { makeroot(x); fa[x] = y; splay(x); } inline void cut(int x, int y) { split(x, y); if(l(y) == x) l(y) = 0, fa[x] = 0; } void change(int x, int y, int weight) { if(findroot(x) != findroot(y)) { ++tot; w[tot] = mk(weight, tot); U[tot] = x; V[tot] = y; sz[tot] = 1; link(x, tot); link(y, tot); now += weight; return; } makeroot(x); access(y); splay(y); PII minVal = mn[y]; if(minVal.fi >= weight) return; cut(minVal.se, V[minVal.se]); cut(minVal.se, U[minVal.se]); now -= minVal.fi; w[minVal.se] = mk(weight, minVal.se); U[minVal.se] = x; V[minVal.se] = y; sz[minVal.se] = 1; link(x, minVal.se); link(y, minVal.se); now += weight; } } lct; int main() { for(int i = 1; i <= 100000; i++) { for(int j = i + i; j <= 100000; j += i) { fac[j].push_back(i); } } lct.init(100000); for(int i = 2; i <= 100000; i++) { for(int j : fac[i]) { lct.change(i, j, j); } ans[i] = now; } while(scanf("%d", &n) != EOF) { printf("%lld\n", ans[n]); } return 0; }