洛谷 P4004 - Hello world!(分块+势能线段树)
作者:互联网
简单分块题,可惜卡了一年的常(
道理很明显,碰到这种不可 polylog 维护的题肯定需要分块,弱化版可见 P3591 POI2015 ODW。而此题又涉及开根号,那又一个一眼的套路:segment beats,这样做法就出来了:设阈值 \(B\),然后。
- 对于 \(k>B\),查询修改都暴力。
- 对于 \(k\le B\),我们先对于所有 \(k_0\in[1,B]\) 建一棵类似于森林出来的东西,即每个点向其 \(k_0\) 级祖先连边,这样连出来肯定是一颗森林,这样查询就可以转化为两条链的求和,可以树状数组维护。而修改等价于找链上第一个 \(\ne 1\) 的位置,暴力链上二分即可。
时间复杂度大概是 \(\dfrac{Qn}{B}·\log n+Q\log n+n\log^2n·B\),实测 \(B=100\) 最优。
感觉此题最难的地方在于写代码。
const int MAXN = 5e4;
const int SQRT = 100;
const int LOG_N = 16;
int n, qu, ord[MAXN + 5], lg[MAXN * 2 + 5]; ll a[MAXN + 5];
int hd[MAXN + 5], to[MAXN * 2 + 5], nxt[MAXN * 2 + 5], ec = 0;
void adde(int u, int v) {to[++ec] = v; nxt[ec] = hd[u]; hd[u] = ec;}
int fa[MAXN + 5][LOG_N + 2], dep[MAXN + 5];
pii st[LOG_N + 2][MAXN * 2 + 5]; int dfn_eu[MAXN + 5], tim_eu;
void dfs0(int x, int f) {
fa[x][0] = f; st[0][dfn_eu[x] = ++tim_eu] = mp(dep[x], x);
for (int e = hd[x]; e; e = nxt[e]) {
int y = to[e]; if (y == f) continue;
dep[y] = dep[x] + 1; dfs0(y, x);
st[0][dfn_eu[x] = ++tim_eu] = mp(dep[x], x);
}
}
pii query_st(int l, int r) {
int k = lg[r - l + 1];
return min(st[k][l], st[k][r - (1 << k) + 1]);
}
int getlca(int x, int y) {
if (dfn_eu[x] > dfn_eu[y]) swap(x, y);
return query_st(dfn_eu[x], dfn_eu[y]).se;
}
int get_kanc(int u, int k) {while (k) u = fa[u][lg[k & (-k)]], k &= (k - 1); return u;}
int getnxt(int u, int v, int k) {
int lc = getlca(u, v);
if (dep[u] - dep[lc] >= k) return get_kanc(u, k);
else if (dep[u] + dep[v] - dep[lc] * 2 <= k) return v;
else return get_kanc(v, dep[v] - dep[lc] - (k - (dep[u] - dep[lc])));
}
int blk, vis[MAXN + 5], bgt[SQRT + 5][MAXN + 5], edt[SQRT + 5][MAXN + 5], tim; vector<int> g[MAXN + 5];
void dfsdfn(int x, int k) {bgt[k][x] = ++tim; vis[x] = 1; for (int y : g[x]) dfsdfn(y, k); edt[k][x] = tim;}
struct fenwick {
ll t[MAXN + 5];
void add(int x, ll v) {for (int i = x; i <= n; i += (i & (-i))) t[i] += v;}
ll query(int x) {ll ret = 0; for (int i = x; i; i &= (i - 1)) ret += t[i]; return ret;}
} T[SQRT + 5];
ll ask(int x, int k) {return T[k].query(bgt[k][x]);}
void upd(int x) {
if (a[x] <= 1) return; ll nw = (ll)sqrt(a[x]);
for (int i = 1; i <= blk; i++) T[i].add(bgt[i][x], -a[x] + nw), T[i].add(edt[i][x] + 1, a[x] - nw);
a[x] = nw;
}
int main() {
for (int i = 2; i <= MAXN * 2; i++) lg[i] = lg[i >> 1] + 1;
scanf("%d", &n); blk = 100;
for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
for (int i = 1, u, v; i < n; i++) scanf("%d%d", &u, &v), adde(u, v), adde(v, u);
dfs0(1, 0);
for (int i = 1; i <= LOG_N; i++) {
for (int j = 1; j <= n; j++) fa[j][i] = fa[fa[j][i - 1]][i - 1];
for (int j = 1; j + (1 << i) - 1 <= n * 2; j++) st[i][j] = min(st[i - 1][j], st[i - 1][j + (1 << i - 1)]);
}
for (int i = 1; i <= n; i++) ord[i] = i;
sort(ord + 1, ord + n + 1, [&](int x, int y) {return dep[x] < dep[y];});
for (int i = 1; i <= blk; i++) {
for (int j = 1; j <= n; j++) g[j].clear(), vis[j] = 0; tim = 0;
for (int j = 1; j <= n; j++) {int anc = get_kanc(j, i); if (anc) g[anc].pb(j);}
for (int j = 1; j <= n; j++) if (!vis[ord[j]]) dfsdfn(ord[j], i);
for (int j = 1; j <= n; j++) T[i].add(bgt[i][j], a[j]), T[i].add(edt[i][j] + 1, -a[j]);
}
scanf("%d", &qu);
while (qu--) {
int opt, u, v, k; scanf("%d%d%d%d", &opt, &u, &v, &k);
if (k > blk) {
if (opt == 0) {
for (int i = u; i != v; i = getnxt(i, v, k)) upd(i);
upd(v);
} else {
ll res = 0;
for (int i = u; i != v; i = getnxt(i, v, k)) res += a[i];
res += a[v]; printf("%lld\n", res);
}
} else {
if (opt == 1) {
int lc = getlca(u, v); ll res = 0; res = ask(u, k);
int anc = get_kanc(u, (dep[u] - dep[lc]) / k * k + k);
res -= ask(anc, k);
int L = k - (dep[u] - dep[lc]) % k;
int R = dep[v] - dep[lc];
if (L <= R) {
R = L + (R - L) / k * k;
res += ask(get_kanc(v, (dep[v] - dep[lc]) - R), k);
anc = get_kanc(v, (dep[v] - dep[lc]) - L + k);
res -= ask(anc, k);
}
if ((dep[u] + dep[v] - dep[lc] * 2) % k) res += a[v];
printf("%lld\n", res);
} else {
int cur = u, lc = getlca(u, v);
while (cur && dep[cur] >= dep[lc]) {
int l = 0, r = (dep[cur] - dep[lc]) / k, p = -1;
ll ss = ask(cur, k);
if (ss - ask(get_kanc(cur, (r + 1) * k), k) == r + 1) break;
while (l <= r) {
int mid = l + r >> 1;
ll sum = ss - ask(get_kanc(cur, (mid + 1) * k), k);
if (sum == mid + 1) l = mid + 1; else r = mid - 1, p = mid;
}
cur = get_kanc(cur, p * k); assert(a[cur] > 1); upd(cur);
cur = get_kanc(cur, k);
}
cur = k - (dep[u] - dep[lc]) % k;
while (cur <= dep[v] - dep[lc]) {
int l = 0, r = (dep[v] - dep[lc] - cur) / k, p = -1;
ll ss = ask(get_kanc(v, dep[v] - dep[lc] - cur + k), k);
if (ask(get_kanc(v, dep[v] - dep[lc] - (cur + r * k)), k) - ss == r + 1) break;
while (l <= r) {
int mid = l + r >> 1;
ll sum = ask(get_kanc(v, dep[v] - dep[lc] - (cur + mid * k)), k) - ss;
if (sum == mid + 1) l = mid + 1;
else p = mid, r = mid - 1;
}
cur += p * k;
assert(a[get_kanc(v, dep[v] - dep[lc] - cur)] > 1);
upd(get_kanc(v, dep[v] - dep[lc] - cur));
cur += k;
}
if ((dep[u] + dep[v] - dep[lc] * 2) % k) upd(v);
}
}
}
return 0;
}
标签:洛谷,cur,int,kanc,dep,MAXN,world,Hello,lc 来源: https://www.cnblogs.com/ET2006/p/luogu-P4004.html