ICode9

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

牛客提高组模拟4 快速访问——一道树剖“板子”题

2021-10-12 21:02:51  阅读:142  来源: 互联网

标签:Head 快速访问 Fa int 树剖 牛客 MAXN LCA dp


link
为什么我会把树剖的常见 trick 忘了啊。。。

trick 1:lca -> x 向上跑 + y 向上跑
trick 2:深度可以用这个点到根点的个数表示

化简一下:\(ans=(d_i+d_j-2d_{LCA(i,j)})^2=d_i^2+d_j^2+4d^2_{LCA(i,j)}+2d_id_j-2d_id_{LCA(i,j)}-2d_jd_{LCA(i,j)}\)

考虑怎么修改/统计答案。第一项可以直接算,因为下标单调第二四项可以直接算。
第五六项实则是一个东西,可以树剖随便维护一下。
第四项可以对于它到根的点全部加上 \(d_x+d_x-1\) 来维护这个平方,其本质是 \(d_x^2-d_{x-1}^2\)。
然后就可以做了。

我考场上降智了想了对操作分块+换根dp+LCA 的 sb \(\mathcal {O}(n\sqrt {n/log_2(n)}log_2(n))\)。
好吧,考下才发现用 Tarjin 求 LCA 不会 MLE,每次用同一个数组即可,可以做到 \(<n\sqrt n \alpha(n)\)。。。算出来是 2e8,但因为递归常数太大分和暴力一样。。。
树剖代码有空再打吧,分块 code:

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#define uint unsigned int
#define LL long long
using namespace std;
const int MAXN = 2e5 + 5;
int n, k, pos[MAXN], L[MAXN], R[MAXN], tot, Fa[MAXN][20], vis[MAXN], t, q, d[MAXN];
LL dp[MAXN], g[MAXN], c[MAXN], ans[MAXN];
int Head[MAXN], Ver[MAXN << 1], Next[MAXN << 1], ggg;
bool f[MAXN];
vector <int> v[MAXN];
// wow.().
void add(int x, int y) { Ver[++ ggg] = y; Next[ggg] = Head[x]; Head[x] = ggg; }
void DFS(int x, int fa) {
	for(int i = Head[x]; i; i = Next[i]) {
		int y = Ver[i]; if(y == fa) continue;
		Fa[y][0] = x; d[y] = d[x] + 1;
		for(int j = 1; j <= q; j ++) Fa[y][j] = Fa[Fa[y][j - 1]][j - 1];
		DFS(y, x);
	}
}
int LCA(int x, int y) {
	if(d[x] < d[y]) swap(x, y);
	for(int i = q; i >= 0; i --) if(d[Fa[x][i]] >= d[y]) x = Fa[x][i];
	if(x == y) return x;
	for(int i = q; i >= 0; i --) if(Fa[x][i] != Fa[y][i]) x = Fa[x][i], y = Fa[y][i];
	return Fa[x][0];
}
void dfs(int x, int fa) {
	for(int i = Head[x]; i; i = Next[i]) {
		int y = Ver[i]; if(y == fa) continue;
		dfs(y, x);
		g[x] += g[y] + c[y]; c[x] += c[y]; dp[x] += dp[y] + 2 * g[y] + c[y];
	}
	c[x] += f[x];
}
void dfs1(int x, int fa) {
	for(int i = Head[x]; i; i = Next[i]) {
		int y = Ver[i]; if(y == fa) continue;
		dp[y] = dp[y] + (dp[x] - dp[y] - 2 * g[y] - c[y]) + 2 * (g[x] - g[y] - c[y]) + (c[x] - c[y]);
		g[y] = g[y] + (g[x] - g[y] - c[y] + (c[x] - c[y]));
		c[y] = c[y] + (c[x] - c[y]);
		dfs1(y, x);
	}
}
LL Query(int l, int r, int id) {
	if(l > r) return 0;
	LL res = 0;
//	for(int i = l; i <= r; i ++) t = LCA(i, id), printf("|%d %d %d %d %d %d|", i, id, t, d[t], d[i], d[id]), res += (LL)(d[i] + d[id] - 2 * d[t]) * (d[i] + d[id] - 2 * d[t]);
//	return res;
	int t = 0;
	if(pos[l] == pos[r]) {
		if(l == L[pos[l]] && r == R[pos[r]]) return 0;
		for(int i = l; i <= r; i ++) t = LCA(i, id), res += (LL)(d[i] + d[id] - 2 * d[t]) * (d[i] + d[id] - 2 * d[t]);
		return res;
	}
	int u = pos[l], v = pos[r];
	if(l != L[u]) {
		for(int i = l; i <= R[u]; i ++) t = LCA(i, id), res += (LL)(d[i] + d[id] - 2 * d[t]) * (d[i] + d[id] - 2 * d[t]);
	}
	if(r != R[v]) {
		for(int i = L[v]; i <= r; i ++) t = LCA(i, id), res += (LL)(d[i] + d[id] - 2 * d[t]) * (d[i] + d[id] - 2 * d[t]);
	}
	return res;
}
int main() {
//	freopen("large_2.in", "r", stdin);
//	freopen("large_2.ans", "w", stdout);
	int x, y; d[1] = 1;
	scanf("%d%d", &n, &k); t = sqrt(n); q = log2(n) + 1;
	for(int i = 1; i <= n; i ++) {
		scanf("%d%d", &x, &y); x ++; y ++; add(x, y); add(y, x);
	}
	DFS(1, -1); 
	for(int i = 1; ; i ++) {
		tot ++; L[tot] = R[tot - 1] + 1; R[tot] = min(n, L[tot] + t);
		if(R[tot] == n)	break;
	}
	for(int i = 1; i <= tot; i ++) L[i] ++, R[i] ++;
	for(int i = 1; i <= tot; i ++) for(int j = L[i]; j <= R[i]; j ++) pos[j] = i;
	for(int i = 1; i <= tot; i ++) {
		for(int j = 1; j <= n + 1; j ++) f[j] = 0, g[j] = c[j] = dp[j] = 0;
		for(int j = L[i]; j <= R[i]; j ++) f[j] = 1;
		dfs(1, -1); dfs1(1, -1);
		for(int j = R[i] + 1; j <= min(L[i] + k, n + 1); j ++) ans[j] += dp[j];
	}
//	memset(ans, 0, sizeof(ans));
	for(int i = 2; i <= n + 1; i ++) {
		int l = max(1, i - k), r = i - 1, u = LCA(1, i);
		if(l == 1) l ++;
		printf("%lld\n", ans[i] + Query(l, r, i) + (LL)(d[i] + d[u] - 2 * d[u]) * (d[i] + d[u] - 2 * d[u]));
	}
	return 0;
}

标签:Head,快速访问,Fa,int,树剖,牛客,MAXN,LCA,dp
来源: https://www.cnblogs.com/Kidulthood/p/15399527.html

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

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

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

ICode9版权所有