其他分享
首页 > 其他分享> > 洛谷 P4004 - Hello world!(分块+势能线段树)

洛谷 P4004 - Hello world!(分块+势能线段树)

作者:互联网

洛谷题面传送门

简单分块题,可惜卡了一年的常(

道理很明显,碰到这种不可 polylog 维护的题肯定需要分块,弱化版可见 P3591 POI2015 ODW。而此题又涉及开根号,那又一个一眼的套路:segment beats,这样做法就出来了:设阈值 \(B\),然后。

时间复杂度大概是 \(\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