I will no longer be a transien|

yabnto

园龄:2年8个月粉丝:14关注:17

点分树(最暴力的一集)

(维什戴尔本色出演)

前情提要

首先,你得学会点分治

引入

当你学会点分治,你会意识到点分治更多的是一种静态的问题

那么对于P6329 【模板】点分树 | 震波这道题,你会显得很无奈,它竟然要动态修改权值

P6329 【模板】点分树 | 震波

那么好,当我们意识到问题后我们就可以开始思考了,考虑到它的树结构是不变的,那么我们可不可以通过存储树结构来解决点分治的静态问题呢?

那么我们的具体时间就变成了:用点分治求出树结构,然后用点分树来解决答案问题

答案如何求

对于一个树结构,我么该如何求答案?

我们很快能想到,因为对于一个查询节点它曾经肯定是一个重心,所以我们可以计算以它为重心时,以它为线段开头的答案,不过,经过它的答案需要它的祖宗来计算。

这下犯了难,假如我们是点分治我们该如何做?

对于祖先节点,当当前节点的设定余波(这里设定余波范围就是以当前节点为子树的根时当前子树的直径的一半)可以波及到祖先节点,那么祖先节点的下一个重心肯定不是他,也就是说在设定余波的范围内不会有自己的祖先(祖宗发射器!!!)考虑设定余波的增长,我们发现按照点分治的树结构,我们的设定余波是两倍两倍增长的,假设真实余波(输入的余波)在设定余波范围内,那么祖先就不可能影响到自己,那么由于设定余波为两倍增长,假设我们暴力跳祖先,我们很快就能想到这是一个倍增,所以时间复杂度是log级别的

最后一个问题,我们暴力跳祖宗,计算答案时需要剪掉跳过来前的节点答案,以防计算bug。

不会吧,还不会?你点分治怎么学的?我不就是用树状数组等数据结构维护这个查找的答案吗?

代码

#include <iostream>
#include <vector>
using namespace std;
const int MaxN = 2e5 + 10, MaxK = 19;
int f[MaxN][MaxK], gfa[MaxN], dfn[MaxN], lg[MaxN], dep[MaxN], sz[MaxN], a[MaxN], cnt, n, m, cn, minx, rt;
vector<int> d[2][MaxN], g[MaxN];
bool vis[MaxN];
int lb(int x) {
return x & (-x);
}
void update(int p, int op, int k, int x) {
for (k++; k <= sz[p]; k += lb(k)) {
d[op][p][k] += x;
}
}
int query(int p, int op, int k, int res = 0) {
for (k = min(sz[p], k + 1); k; k -= lb(k)) {
res += d[op][p][k];
}
return res;
}
int mindep(int a, int b) {
return dep[a] < dep[b] ? a : b;
}
void DFS(int x, int fa = 0) {
f[++cnt][0] = x, dfn[x] = cnt;
for (int i : g[x]) {
if (i == fa) continue;
dep[i] = dep[x] + 1, DFS(i, x), f[++cnt][0] = x;
}
}
void find(int x, int fa = 0, int maxsz = 0) {
sz[x] = 1;
for (int i : g[x]) {
if (vis[i] || i == fa) continue;
find(i, x), sz[x] += sz[i], maxsz = max(maxsz, sz[i]);
}
maxsz = max(maxsz, n - sz[x]);
(maxsz < minx) && (minx = maxsz, rt = x);
}
void S(int x) {
vis[x] = 1, sz[x] = n + 1, d[0][x].resize(sz[x] + 1), d[1][x].resize(sz[x] + 1);
for (int i : g[x]) {
if (vis[i]) continue;
n = sz[i], minx = 1e9, find(i), gfa[rt] = x;
S(rt);
}
}
int dis(int x, int y) {
if (dfn[x] > dfn[y]) swap(x, y);
int dx = dfn[x], dy = dfn[y], len = dy - dx + 1, lca = mindep(f[dx][lg[len]], f[dy - (1 << lg[len]) + 1][lg[len]]);
return dep[x] + dep[y] - dep[lca] * 2;
}
void modify(int x, int w) {
for (int i = x; i; i = gfa[i]) {
update(i, 0, dis(x, i), w);
}
for (int i = x; gfa[i]; i = gfa[i]) {
update(i, 1, dis(x, gfa[i]), w);
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m, cn = n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1, u, v; i < n; i++) {
cin >> u >> v;
g[u].push_back(v), g[v].push_back(u);
}
DFS(1);
for (int j = 2; j <= cnt + 1; j++) {
lg[j] = lg[j >> 1] + 1;
}
for (int j = 1; j < MaxK; j++) {
for (int i = 1; i + (1 << j) - 1 <= cnt; i++) {
f[i][j] = mindep(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
}
minx = 1e9, find(1), S(rt);
for (int i = 1; i <= cn; i++) {
modify(i, a[i]);
}
for (int i = 1, op, x, k, lst = 0; i <= m; i++) {
cin >> op >> x >> k, x ^= lst, k ^= lst;
if (op) {
modify(x, k - a[x]), a[x] = k;
} else {
lst = query(x, 0, k);
for (int i = x; gfa[i]; i = gfa[i]) {
(k >= dis(x, gfa[i])) && (lst += query(gfa[i], 0, k - dis(x, gfa[i])) - query(i, 1, k - dis(x, gfa[i])));
}
cout << lst << '\n';
}
}
return 0;
}

P6626 [省选联考 2020 B 卷] 消息传递

那么这道题就很简单了,只是k内,变成了第k

代码

#include <iostream>
#include <vector>
using namespace std;
const int MaxN = 2e5 + 10, MaxK = 19;
int f[MaxN][MaxK], gfa[MaxN], dfn[MaxN], lg[MaxN], dep[MaxN], sz[MaxN], cnt, n, m, cn, minx, t, rt;
vector<int> d[2][MaxN], g[MaxN];
bool vis[MaxN];
int lb(int x) {
return x & (-x);
}
void update(int p, int op, int k, int x) {
(k <= sz[p]) && (d[op][p][k] += x);
}
int query(int p, int op, int k, int res = 0) {
(k <= sz[p]) && (res += d[op][p][k]);
return res;
}
int mindep(int a, int b) {
return dep[a] < dep[b] ? a : b;
}
void DFS(int x, int fa = 0) {
f[++cnt][0] = x, dfn[x] = cnt;
for (int i : g[x]) {
if (i == fa) continue;
dep[i] = dep[x] + 1, DFS(i, x), f[++cnt][0] = x;
}
}
void find(int x, int fa = 0, int maxsz = 0) {
sz[x] = 1;
for (int i : g[x]) {
if (vis[i] || i == fa) continue;
find(i, x), sz[x] += sz[i], maxsz = max(maxsz, sz[i]);
}
maxsz = max(maxsz, n - sz[x]);
(maxsz < minx) && (minx = maxsz, rt = x);
}
void S(int x) {
vis[x] = 1, sz[x] = n + 1, vector<int>().swap(d[0][x]), vector<int>().swap(d[1][x]), d[0][x].resize(sz[x] + 1), d[1][x].resize(sz[x] + 1);
for (int i : g[x]) {
if (vis[i]) continue;
n = sz[i], minx = 1e9, find(i), gfa[rt] = x;
S(rt);
}
}
int dis(int x, int y) {
if (dfn[x] > dfn[y]) swap(x, y);
int dx = dfn[x], dy = dfn[y], len = dy - dx + 1, lca = mindep(f[dx][lg[len]], f[dy - (1 << lg[len]) + 1][lg[len]]);
return dep[x] + dep[y] - dep[lca] * 2;
}
void modify(int x, int w) {
for (int i = x; i; i = gfa[i]) {
update(i, 0, dis(x, i), w);
}
for (int i = x; gfa[i]; i = gfa[i]) {
update(i, 1, dis(x, gfa[i]), w);
}
}
void clear() {
for (int i = 1; i <= n; i++) {
vector<int>().swap(g[i]);
vis[i] = gfa[i] = dfn[i] = dep[i] = sz[i] = 0;
d[0][i].clear(), d[1][i].clear();
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
for (int j = 2; j < MaxN; j++) {
lg[j] = lg[j >> 1] + 1;
}
for (cin >> t; t; t--) {
cin >> n >> m, cn = n, cnt = 0;
clear();
for (int i = 1, u, v; i < n; i++) {
cin >> u >> v;
g[u].push_back(v), g[v].push_back(u);
}
DFS(1);
for (int j = 1; j < MaxK; j++) {
for (int i = 1; i + (1 << j) - 1 <= cnt; i++) {
f[i][j] = mindep(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
}
minx = 1e9, find(1), S(rt);
for (int i = 1; i <= cn; i++) {
modify(i, 1);
}
for (int i = 1, x, k, ans = 0; i <= m; i++) {
cin >> x >> k;
ans = query(x, 0, k);
for (int i = x; gfa[i]; i = gfa[i]) {
int len = k - dis(x, gfa[i]);
(len >= 0) && (ans += query(gfa[i], 0, len) - query(i, 1, len));
}
cout << ans << '\n';
}
}
return 0;
}

一些对于点分树的幻想

P10930 异象石

一开始看到这个题,我会觉得很熟悉,所以我们思考到了点分树,可是,过于暴力,导致这个是失败的

本文作者:yabnto

本文链接:https://www.cnblogs.com/ybtarr/p/18736245

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   yabnto  阅读(13)  评论(0编辑  收藏  举报
  1. 1 イエスタデイ(翻自 Official髭男dism) 茶泡饭,春茶,kobasolo
  2. 2 光辉岁月 Audio artist
  3. 3 名前を呼ぶよ Audio artist
  4. 4 战歌 Audio artist
  5. 5 時を越えた想い Audio artist
  6. 6 所念皆星河 Audio artist
  7. 7 See you again Audio artist
名前を呼ぶよ - Audio artist
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

Not available

点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起