博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ4372: 烁烁的游戏【动态点分治】
阅读量:5157 次
发布时间:2019-06-13

本文共 4751 字,大约阅读时间需要 15 分钟。

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
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
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;}

转载于:https://www.cnblogs.com/dream-maker-yk/p/10053190.html

你可能感兴趣的文章
.NET CLR基本术语
查看>>
ubuntu的home目录下,Desktop等目录消失不见
查看>>
建立,查询二叉树 hdu 5444
查看>>
[Spring框架]Spring 事务管理基础入门总结.
查看>>
2017.3.24上午
查看>>
Python-常用模块及简单的案列
查看>>
LeetCode 159. Longest Substring with At Most Two Distinct Characters
查看>>
LeetCode Ones and Zeroes
查看>>
基本算法概论
查看>>
jquery动态移除/增加onclick属性详解
查看>>
JavaScript---Promise
查看>>
暖暖的感动
查看>>
Java中的日期和时间
查看>>
Django基于admin的stark组件创建(一)
查看>>
PAT L2-016 愿天下有情人都是失散多年的兄妹
查看>>
抛弃IIS,利用FastCGI让Asp.net与Nginx在一起
查看>>
C. Tanya and Toys_模拟
查看>>
springboot jar包运行中获取资源文件
查看>>
基于FPGA实现的高速串行交换模块实现方法研究
查看>>
Java Scala获取所有注解的类信息
查看>>