BZOJ4372: 烁烁的游戏【动态点分治】
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: 烁烁的游戏【动态点分治】的更多相关文章
- BZOJ4372烁烁的游戏——动态点分治+线段树(点分树套线段树)
题目描述 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠.皮皮鼠会被 ...
- [bzoj4372] 烁烁的游戏 [动态点分治+线段树+容斥原理]
题面 传送门 思路 观察一下题目,要求的是修改"距离点$u$的距离一定的点权值",那这个就不能用传统的dfs序类算法+线段树维护,因为涉及到向父亲回溯的问题 看到和树上距离相关的东 ...
- [BZOJ4372]烁烁的游戏(动态点分治+线段树)
和[BZOJ3730]震波几乎一样,每个点建两棵线段树分别代表它的管辖范围内以它为LCA的路径的贡献和它对父亲的贡献. 注意点分树上的点的距离在原树上不单调,所以不能有若距离超出限制就break之类的 ...
- BZOJ4372: 烁烁的游戏(动态点分治)
Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮 ...
- 【BZOJ4372】烁烁的游戏 动态树分治+线段树
[BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距 ...
- 【bzoj4372】烁烁的游戏 动态点分治+线段树
题目描述 给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:Q x:询问x的点权.M x d w:将树上与节点x距离不超过d的节点的点权均加上w. 输入 第一行两个正整数:n,m接下来的n-1 ...
- bzoj 4372: 烁烁的游戏 动态点分治_树链剖分_线段树
[Submit][Status][Discuss] Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠. 题意: 给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠. 烁烁他每次会跳 ...
- bzoj 4372 烁烁的游戏——动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 和 bzoj 3070 震波 是一个套路.注意区间修改的话,树状数组不能表示 dis ...
- bzoj 4372 烁烁的游戏 —— 动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 本以为和 bzoj3730 一样,可以直接双倍经验了: 但要注意一下,树状数组不能查询 ...
随机推荐
- MySQL的GTID复制
从mysql5.6开始引入全局事务标识符(GTID),即每个事务都有一个唯一的标识符.服务器上的每个事务都被分配一个唯一的事务标识符,这是一个64位非零的数值,根据事务提交的顺序分配.GTID的构成是 ...
- 20145221 《Java程序设计》实验报告一:Java开发环境的熟悉(Windows+IDEA)
20145221 <Java程序设计>实验报告一:Java开发环境的熟悉(Windows+IDEA) 实验要求 使用JDK编译.运行简单的Java程序: 使用IDEA 编辑.编译.运行.调 ...
- VC++ 在两个程序中 传送字符串等常量值的方法:使用了 WM_COPYDATA 消息(转载)
转载:http://www.cnblogs.com/renyuan/p/5037536.html VC++ 在两个程序中 传递字符串等常量值的方法:使用了 WM_COPYDATA 消息的 消息作用: ...
- vSphere Client开启虚拟机提示:出现了常规系统错误: 由于目标计算机积极拒绝,无法连接。
进入VCenter Server服务器上 进入服务管理器,查看 VMware vCenter workflow manager 是否启动,如未启动,则改为启动,问题得以解决 再次启动虚拟机,已启动!
- 【转载】hibernate缓存机制
一级缓存(session级别) 我们来看看hibernate提供的一级缓存 //此时会发出一条sql,将所有学生全部查询出来,并放到session的一级缓存当中.当再次查询学生信息时,会首先去缓存中看 ...
- Flask: socket.error: [Errno 48] Address already in use 问题
参考: Mac OSX 解决socket.error: [Errno 48] Address already in use问题 Mac OS X中解决socket.error: [Errno 48] ...
- 解决 docker: Error response from daemon: ... : net/http: TLS handshake timeout.
参考:解决 Docker pull 出现的net/http: TLS handshake timeout 的一个办法 问题: 执行 $ sudo docker run hello-world 时出现: ...
- 【转载】解决telnet无法连接 Connection refused
原文:解决telnet无法连接 Connection refused telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式.它为用户提供了在本地计算机上完成 ...
- Template Method(模板方法)
意图: 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.TemplateMethod 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 适用性: 一次性实现一个算法的不变的部分, ...
- 一定要用Windows自带的记事本编辑 applicationHost.config
访问IIS时,发生了一个 HipIISEngineStub.dll不能读取的问题.(Windows Event可以确认). 很容易在网上找到了对策, http://chrisfleischhacker ...