ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-07-10 22:03:45  阅读:197  来源: 互联网

标签:洛谷 cur int kanc dep MAXN world Hello lc


洛谷题面传送门

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

道理很明显,碰到这种不可 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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有