Description

背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠。

题意:

给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠。

烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠。皮皮鼠会被烁烁吸引,所以会一直待在节点上不动。

烁烁很好奇,在当前时刻,节点u有多少个他的好朋友---皮皮鼠。

大意:

给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:

Q x:询问x的点权。

M x d w:将树上与节点x距离不超过d的节点的点权均加上w。

Input

第一行两个正整数:n,m

接下来的n-1行,每行三个正整数u,v,代表u,v之间有一条边。

接下来的m行,每行给出上述两种操作中的一种。

Output

对于每个Q操作,输出当前x节点的皮皮鼠数量。

Sample Input

7 6

1 2

1 4

1 5

2 3

2 7

5 6

M 1 1 2

Q 5

M 2 2 3

Q 3

M 1 2 1

Q 2

Sample Output

2

3

6

HINT

数据范围:

\(n,m<=10^5,|w|<=10^4\)

注意:w不一定为正整数,因为烁烁可能把皮皮鼠吓傻了。


思路

首先我们就发现操作是把距离到一个点不超过k的点权值加上一个w,然后查询一个点的权值

首先我们就发现对于每个点可以算出来距离小于等于k的点被加上了多少

然后查询的时候我们就只需要看每个节点和查询节点的距离在那个节点上被添加了多少次就可以了

这个过程是可以用动态点分治来优化的

可以用欧拉序处理掉LCA,然后因为每次我们都是区间加,但点查询,所以就可以用树状数组来维护了

但是注意树状数组的大小需要动态控制


注意下细节就可以了


#include<bits/stdc++.h>

using namespace std;

int read() {
int res = 0, w = 1; char c = getchar();
while (!isdigit(c) && c != '-') c = getchar();
if (c == '-') w = -1, c = getchar();
while (isdigit(c)) res = (res << 1) + (res << 3) + c - '0', c = getchar();
return res * w;
} const int N = 1e5 + 10;
const int LOG = 20; struct Edge {
int v, nxt;
Edge(int v = 0, int nxt = 0): v(v), nxt(nxt) {}
} E[N << 1];
int head[N], tot = 0;
int n, q;
char c[10]; void addedge(int u, int v) {
E[++tot] = Edge(v, head[u]);
head[u] = tot;
} namespace LCA { struct Node {
int id, depth;
Node(int id = 0, int depth = 0): id(id), depth(depth) {}
bool operator < (const Node b) const {
return depth < b.depth;
}
} ST[N << 1][LOG];
int first[N], dep[N], log[N << 1], len; void dfs(int u, int fa) {
dep[u] = dep[fa] + 1;
ST[++len][0] = Node(u, dep[u]);
first[u] = len;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == fa) continue;
dfs(v, u);
ST[++len][0] = Node(u, dep[u]);
}
} void init() {
dfs(1, 0);
log[1] = 0;
for (int i = 2; i <= len; i++) log[i] = log[i >> 1] + 1;
for (int j = 1; (1 << j) <= len; j++) {
for (int i = 1; i + (1 << j) - 1 <= len; i++) {
ST[i][j] = min(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
}
}
} int getdis(int u, int v) {
if (first[u] < first[v]) swap(u, v);
int k = log[first[u] - first[v] + 1];
int lca = min(ST[first[v]][k], ST[first[u] - (1 << k) + 1][k]).id;
return dep[u] + dep[v] - (dep[lca] << 1);
} } namespace Tree_Devide { int father[N], dep[N], maxdep;
int siz[N], F[N], siz_all, rt;
bool vis[N];
vector<int> bit[2][N]; void modify(int x, int vl, int typ, int u) {
int len = bit[typ][u].size();
while (x < len) {
bit[typ][u][x] += vl;
x += x & (-x);
}
} void modify(int l, int r, int vl, int typ, int u) {
modify(l + 1, vl, typ, u);
modify(r + 2, -vl, typ, u);
} int query(int x, int typ, int u) {
int len = bit[typ][u].size(), res = 0;
x = min(x + 1, len - 1);
while (x) {
res += bit[typ][u][x];
x -= x & (-x);
}
return res;
} void getsiz(int u, int fa) {
siz[u] = 1;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == fa || vis[v]) continue;
dep[v] = dep[u] + 1;
maxdep = max(maxdep, dep[v]);
getsiz(v, u);
siz[u] += siz[v];
}
} void getroot(int u, int fa) {
F[u] = 0;
dep[u] = dep[fa] + 1;
maxdep = max(maxdep, dep[u]);
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == fa || vis[v]) continue;
getroot(v, u);
F[u] = max(F[u], siz[v]);
}
F[u] = max(F[u], siz_all - siz[u]);
if (F[u] < F[rt]) rt = u;
} void solve(int u, int fa) {
father[u] = fa;
vis[u] = 1;
maxdep = dep[u] = 0;
getsiz(u, 0);
bit[0][u].resize(maxdep + 4);
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (vis[v]) continue;
F[rt = 0] = siz_all = siz[v];
maxdep = 0;
getroot(v, 0);
bit[1][rt].resize(maxdep + 4);
solve(rt, u);
}
} void init() {
getsiz(1, 0);
F[rt = 0] = siz_all = n;
getroot(1, 0);
solve(rt, 0);
} void modify_tree(int u, int k, int num) {
modify(0, k, num, 0, u);
for (int cur = u; father[cur]; cur = father[cur]) {
int dis = LCA::getdis(u, father[cur]);
if (k >= dis) {
modify(0, k - dis, num, 0, father[cur]);
modify(0, k - dis, num, 1, cur);
}
}
} int query_tree(int u) {
int res = query(0, 0, u);
for (int cur = u; father[cur]; cur = father[cur]) {
int dis = LCA::getdis(u, father[cur]);
res += query(dis, 0, father[cur]);
res -= query(dis, 1, cur);
}
return res;
} } int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
n = read(), q = read();
for (int i = 1; i < n; i++) {
int u = read(), v = read();
addedge(u, v);
addedge(v, u);
}
LCA::init();
Tree_Devide::init();
while (q--) {
scanf("%s", c);
if (c[0] == 'M') {
int u = read(), k = read(), num = read();
Tree_Devide::modify_tree(u, k, num);
} else {
int u = read();
printf("%d\n", Tree_Devide::query_tree(u));
}
}
return 0;
}

BZOJ4372: 烁烁的游戏【动态点分治】的更多相关文章

  1. BZOJ4372烁烁的游戏——动态点分治+线段树(点分树套线段树)

    题目描述 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠.皮皮鼠会被 ...

  2. [bzoj4372] 烁烁的游戏 [动态点分治+线段树+容斥原理]

    题面 传送门 思路 观察一下题目,要求的是修改"距离点$u$的距离一定的点权值",那这个就不能用传统的dfs序类算法+线段树维护,因为涉及到向父亲回溯的问题 看到和树上距离相关的东 ...

  3. [BZOJ4372]烁烁的游戏(动态点分治+线段树)

    和[BZOJ3730]震波几乎一样,每个点建两棵线段树分别代表它的管辖范围内以它为LCA的路径的贡献和它对父亲的贡献. 注意点分树上的点的距离在原树上不单调,所以不能有若距离超出限制就break之类的 ...

  4. BZOJ4372: 烁烁的游戏(动态点分治)

    Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮 ...

  5. 【BZOJ4372】烁烁的游戏 动态树分治+线段树

    [BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距 ...

  6. 【bzoj4372】烁烁的游戏 动态点分治+线段树

    题目描述 给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:Q x:询问x的点权.M x d w:将树上与节点x距离不超过d的节点的点权均加上w. 输入 第一行两个正整数:n,m接下来的n-1 ...

  7. bzoj 4372: 烁烁的游戏 动态点分治_树链剖分_线段树

    [Submit][Status][Discuss] Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠. 题意: 给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠. 烁烁他每次会跳 ...

  8. bzoj 4372 烁烁的游戏——动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 和 bzoj 3070 震波 是一个套路.注意区间修改的话,树状数组不能表示 dis ...

  9. bzoj 4372 烁烁的游戏 —— 动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 本以为和 bzoj3730 一样,可以直接双倍经验了: 但要注意一下,树状数组不能查询 ...

随机推荐

  1. vs2010中如何编写C语言程序

    File->New->Project 在打开的New Project对话框中最左侧一栏中选择Visual C++下面的CLR,之后在其右侧的区域中选择CLR Empty Applicati ...

  2. vue小toast插件报错runtine-only

    var Toast={}; Toast.install = function (Vue, options) { let opt = { defaultType:'bottom', // 默认显示位置 ...

  3. zw版【转发·台湾nvp系列Delphi例程】HALCON SetIcon1

    zw版[转发·台湾nvp系列Delphi例程]HALCON SetIcon1 procedure TForm1.Button1Click(Sender: TObject);var img : HIma ...

  4. A Practical Guide to Support Vector Classi cation

    <A Practical Guide to Support Vector Classication>是一篇libSVM使用入门教程以及一些实用技巧. 1. Basic Kernels: ( ...

  5. java分布式系统开关功能设计(服务升降级)

     ​问题一:在单个java系统中如何实现开关功能? ​    ​其实对于开关来说,对应Java中的类型,很好映射,就是一个boolean值,在需要做开关操作的地方,调用这个属性,判断状态,然后走相应的 ...

  6. UVa 11248 网络扩容(最大流(需要优化))

    https://vjudge.net/problem/UVA-11248 题意: 给定一个有向网络,每条边均有一个容量.问是否存在一个从点1到点N,流量为C的流.如果不存在,是否可以恰好修改一条弧的容 ...

  7. jmeter 网速

    有人知道在jmeter 哪个里面哦 JMeterPlugins里面 network

  8. pysam - 多种格式基因组数据(sam/bam/vcf/bcf/cram/…)读写与处理模块(python)--转载

    pysam 模块介绍!!!! http://pysam.readthedocs.io/en/latest/index.html 在开发基因组相关流程或工具时,经常需要读取.处理和创建bam.vcf.b ...

  9. Maximum Depth of Binary Tree,求树的最大深度

    算法分析:求树的最小最大深度时候,都有两种方法,第一种是递归思想.树最大最小深度,即为它的子树的最大最小深度+1,是动态规划的思想.还有一种方法是层序遍历树,只不过求最小深度时,找到第一个叶子节点就可 ...

  10. 带宽检测工具iftop

    1.安装 # yum install iftop –y 2.使用 # iftop -i eth0 -n # iftop -i eth0 -P 说明: 中间的<= =>这两个左右箭头,表示的 ...