标签:cassert sum long 改变 -- 官方 复杂 题解 插入
记\(K = \max{k_i}\)
貌似比原题解的复杂度正确一点,\(O(K\log^2 K )\)的
给一棵树,\(i\)与\(\dfrac{i}{minFactor(i)}\)连边
给\(n\)个关键点,每个点的位置是\(k_i!\)
求一个点到所有关键点距离最短(重复算多次),\(n \leq 10^6, k_i \leq 5\times10^3\)
首先发现,LCA的深度就是公共最大质因子个数,每个点的分叉的位置就是第一次质因子改变的地方。如\(5^2\)变成\(5^3\)就会分叉。
依次插入\(1!\)到 \(5000!\),设插入\(i!\)
显然,插入一个质数一定会连接\(1\),否则对\(i\)做质因子分解,第一次改变的质因子一定是\(i\)的最大质因子
所以可以求出这个质因子,\((i-1)!\)中大于等于它的质因子不会分叉,然后在这个位置分叉(可能在一条虚边上,需要拆开边,开一个新点)。
用树状数组维护\((i-1)!\)的各个质因子出现个数,就可以快速求出公共部分的长度,记为\(com\),然后将\((i-1)!\)的质因子个数和记为\(facSum\),\(facSum - com\)就是要跳的步数,暴力向上跳,然后需要开新点就开新点,不需要就直接挂下面就好了,连一条长为\(facSum' - com\)(\(facSum'\)为\(i!\)的质因子个数)即可,这里有点类似SAM插入。
最后从根节点开始贪心地进入\(size \geq \lfloor \dfrac{n}{2} \rfloor\)的子树即可。
CF提交记录
好像写长了点...
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cassert>
using namespace std;
#define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
typedef long long ll;
namespace io {
const int SIZE = (1 << 21) + 1;
char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
char getc () {return gc();}
inline void flush () {fwrite (obuf, 1, oS - obuf, stdout); oS = obuf;}
inline void putc (char x) {*oS ++ = x; if (oS == oT) flush ();}
template <class I> inline void gi (I &x) {for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;}
template <class I> inline void print (I x) {if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;while (x) qu[++ qr] = x % 10 + '0', x /= 10;while (qr) putc (qu[qr --]);}
struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: gi; using io :: putc; using io :: print; using io :: getc;
template<class T> void upmax(T &x, T y){x = x>y ? x : y;}
template<class T> void upmin(T &x, T y){x = x<y ? x : y;}
const int N = 5005, V = 5000;
bool np[N];
int p[N], pid[N], minFac[N], pc = 0;
void pre(){
np[0] = np[1] = true;
for(int i=2; i<=V; i++){
if(!np[i]) p[++pc] = i, pid[i] = pc;
for(int j=1; j<=pc && i * p[j] <= V; j++){
np[i * p[j]] = true;
minFac[i * p[j]] = p[j];
if(i % p[j] == 0) break;
}
}
}
int fa[N * 2], len[N * 2], cnt[N];
int tr[N], sz[N*2];
void modify(int p){
// printf("Modify %d\n", p);
p = pc - p + 1;
// assert(p > 0 && p <= pc);
for(; p<=pc; p += p & -p) ++tr[p];
}
int query(int p){
p = pc - p + 1;
int res = 0;
for(; p; p ^= (p & -p)) res += tr[p];
return res;
}
struct Edge{
int v, w;
Edge(){}
Edge(int _v, int _w) : v(_v), w(_w) {}
};
vector<Edge> G[N*2];
int nc = 1;
ll res = 0;
int Node[N], Sum[N];
int getDepth(int x){
int res = 0;
while(x != 1) res += len[x], x = fa[x];
return res;
}
void build(){
nc = 1; sz[nc] = cnt[1] + cnt[0];
int facSum = 0;
for(int i=2; i<=V; i++){
if(!np[i]){
int now = ++nc;
fa[now] = 1; len[now] = ++facSum;
sz[now] = cnt[i];
modify(pid[i]);
res += 1LL * facSum * cnt[i];
continue;
}
int v = i, facCnt = 0;
while(np[v]) v /= minFac[v], ++facCnt;
++facCnt;
int com = query(pid[v]), diff = facSum - com;
int x = nc;
while(diff >= len[x])
diff -= len[x], x = fa[x];
if(diff == 0){
int now = ++nc;
fa[now] = x;
facSum += facCnt; len[now] = facSum - com;
sz[now] = cnt[i];
}
else{
int p = ++nc;
fa[p] = fa[x]; len[p] = len[x] - diff;
fa[x] = p; len[x] = diff;
int now = ++nc;
fa[now] = p;
facSum += facCnt; len[now] = facSum - com;
sz[now] = cnt[i];
}
v = i;
while(np[v]) modify(pid[minFac[v]]), v /= minFac[v];
modify(pid[v]);
res += 1LL * facSum * cnt[i];
}
}
void dfs(int x, int fa){
for(const Edge &e : G[x]){
if(e.v == fa) continue;
dfs(e.v, x);
sz[x] += sz[e.v];
}
}
int main(){
// File("cf1292d");
int n;
gi(n);
for(int i=1, x; i<=n; i++) gi(x), ++cnt[x];
pre();
build();
for(int i=nc; i>=2; i--) G[fa[i]].emplace_back(i, len[i]);
dfs(1, 1);
int p = 1;
bool flag = true;
while(flag){
flag = false;
for(const Edge &e : G[p]){
if(sz[e.v] > (n >> 1)){
res -= 1LL * e.w * ((sz[e.v] << 1) - n);
p = e.v;
flag = true;
break;
}
}
}
printf("%lld\n", res);
return 0;
}
标签:cassert sum long 改变 -- 官方 复杂 题解 插入
原文地址:https://www.cnblogs.com/RiverHamster/p/sol-cf1292d.html