【bzoj3730】震波 动态点分治+线段树
题目描述
在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
为了体现程序的在线性,操作中的x、y、k都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为0。
输入
第一行包含两个正整数N和M。
第二行包含N个正整数,第i个数表示value[i]。
接下来N-1行,每行包含两个正整数u、v,表示u和v之间有一条无向边。
接下来M行,每行包含三个数,表示M次操作。
输出
包含若干行,对于每个询问输出一行一个正整数表示答案。
样例输入
8 1
1 10 100 1000 10000 100000 1000000 10000000
1 2
1 3
2 4
2 5
3 6
3 7
3 8
0 3 1
样例输出
11100101
题解
动态点分治+线段树
考虑点分树的某一层除了查询点对应子树的部分,它们到查询点的路径都是:该点-该层节点-查询点。
因此求出该层节点到查询点的距离,就知道了该点到该层节点的距离的范围。
于是可以对于每一个节点按照距离维护一棵线段树,表示该节点点分树子树内到其距离为某值的所有节点的权值和。
一个问题:如何表示点分树除了查询点子树的部分?
静态点分治提供了一个很好的方法:容斥。
因此还要对每个节点维护另一颗线段树,表示该节点点分树子树内到其父亲节点距离为某值的所有节点的权值和。查询时减一下即可。
另一个问题:如何快速求出两点间距离?使用RMQLCA,预处理后 $O(1)$ 查询LCA深度即可。
时间复杂度 $O(n\log^2n)$
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
#define lson l , mid , ls[x]
#define rson mid + 1 , r , rs[x]
using namespace std;
int n , head[N] , to[N << 1] , next[N << 1] , cnt , deep[N] , pos[N] , md[20][N << 1] , log[N << 1] , tot;
int v[N] , vis[N] , si[N] , ms[N] , ts , root , fa[N] , ra[N] , rb[N];
int ls[N * 200] , rs[N * 200] , sum[N * 200] , tp;
inline void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void dfs(int x , int last)
{
int i;
pos[x] = ++tot , md[0][tot] = deep[x];
for(i = head[x] ; i ; i = next[i])
if(to[i] != last)
deep[to[i]] = deep[x] + 1 , dfs(to[i] , x) , md[0][++tot] = deep[x];
}
inline int dis(int x , int y)
{
int t = deep[x] + deep[y] , k;
x = pos[x] , y = pos[y];
if(x > y) swap(x , y);
k = log[y - x + 1];
return t - (min(md[k][x] , md[k][y - (1 << k) + 1]) << 1);
}
void update(int p , int a , int l , int r , int &x)
{
if(!x) x = ++tp;
sum[x] += a;
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) update(p , a , lson);
else update(p , a , rson);
}
int query(int p , int l , int r , int x)
{
if(!x) return 0;
if(l == r) return sum[x];
int mid = (l + r) >> 1;
if(p <= mid) return query(p , lson);
else return query(p , rson) + sum[ls[x]];
}
void getroot(int x , int last)
{
int i;
si[x] = 1 , ms[x] = 0;
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]] && to[i] != last)
getroot(to[i] , x) , si[x] += si[to[i]] , ms[x] = max(ms[x] , si[to[i]]);
ms[x] = max(ms[x] , ts - si[x]);
if(ms[x] < ms[root]) root = x;
}
void deal(int x , int last , int p)
{
update(dis(x , p) , v[x] , 0 , n - 1 , ra[p]);
if(fa[p]) update(dis(x , fa[p]) , v[x] , 0 , n - 1 , rb[p]);
int i;
si[x] = 1;
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]] && to[i] != last)
deal(to[i] , x , p) , si[x] += si[to[i]];
}
void work(int x)
{
int i;
deal(x , 0 , x) , vis[x] = 1;
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]])
root = 0 , ts = si[to[i]] , getroot(to[i] , 0) , fa[root] = x , work(root);
}
inline void modify(int x , int y)
{
int i;
for(i = x ; i ; i = fa[i])
{
update(dis(x , i) , y - v[x] , 0 , n - 1 , ra[i]);
if(fa[i]) update(dis(x , fa[i]) , y - v[x] , 0 , n - 1 , rb[i]);
}
v[x] = y;
}
inline int solve(int x , int k)
{
int i , ans = 0;
for(i = x ; i ; i = fa[i])
{
if(dis(x , i) <= k) ans += query(k - dis(x , i) , 0 , n - 1 , ra[i]);
if(fa[i] && dis(x , fa[i]) <= k) ans -= query(k - dis(x , fa[i]) , 0 , n - 1 , rb[i]);
}
return ans;
}
int main()
{
int m , i , j , opt , x , y , last = 0;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &v[i]);
for(i = 1 ; i < n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
dfs(1 , 0);
for(i = 2 ; i <= tot ; i ++ ) log[i] = log[i >> 1] + 1;
for(i = 1 ; (1 << i) <= tot ; i ++ )
for(j = 1 ; j <= tot - (1 << i) + 1 ; j ++ )
md[i][j] = min(md[i - 1][j] , md[i - 1][j + (1 << (i - 1))]);
ms[0] = 1 << 30 , ts = n , getroot(1 , 0) , work(root);
while(m -- )
{
scanf("%d%d%d" , &opt , &x , &y) , x ^= last , y ^= last;
if(!opt) printf("%d\n" , last = solve(x , y));
else modify(x , y);
}
return 0;
}
【bzoj3730】震波 动态点分治+线段树的更多相关文章
- BZOJ3730震波——动态点分治+线段树(点分树套线段树)
题目描述 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着时代的发展,城市 ...
- bzoj3730 震波 [动态点分治,树状数组]
传送门 思路 如果没有强制在线的话可以离线之后CDQ分治随便搞. 有了强制在线之后--可能可以二维线段树?然而我不会算空间. 然后我们莫名其妙地想到了动态点分治,然后这题就差不多做完了. 点分树有一个 ...
- BZOJ 4372/3370 烁烁的游戏/震波 (动态点分治+线段树)
烁烁的游戏 题目大意: 给你一棵$n$个节点的树,有$m$次操作,询问某个节点的权值,或者将与某个点$x$距离不超过$d$的所有节点的权值都增加$w$ 动态点分裸题 每个节点开一棵权值线段树 对于修改 ...
- 【loj6145】「2017 山东三轮集训 Day7」Easy 动态点分治+线段树
题目描述 给你一棵 $n$ 个点的树,边有边权.$m$ 次询问,每次给出 $l$ .$r$ .$x$ ,求 $\text{Min}_{i=l}^r\text{dis}(i,x)$ . $n,m\le ...
- 【bzoj4372】烁烁的游戏 动态点分治+线段树
题目描述 给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:Q x:询问x的点权.M x d w:将树上与节点x距离不超过d的节点的点权均加上w. 输入 第一行两个正整数:n,m接下来的n-1 ...
- BZOJ4372烁烁的游戏——动态点分治+线段树(点分树套线段树)
题目描述 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠.皮皮鼠会被 ...
- [bzoj4372] 烁烁的游戏 [动态点分治+线段树+容斥原理]
题面 传送门 思路 观察一下题目,要求的是修改"距离点$u$的距离一定的点权值",那这个就不能用传统的dfs序类算法+线段树维护,因为涉及到向父亲回溯的问题 看到和树上距离相关的东 ...
- 2019ICPC上海网络赛 A Lightning Routing I 点分树(动态点分治)+线段树
题意 给一颗带边权的树,有两种操作 \(C~e_i~w_i\),将第\(e_i\)条边的边权改为\(w_i\). \(Q~v_i\),询问距\(v_i\)点最远的点的距离. 分析 官方题解做法:动态维 ...
- bzoj 3730: 震波 动态点分治_树链剖分_线段树
##### 题目描述 : 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着 ...
随机推荐
- PHP学习笔记之析构函数以及static,self,parent关键字
引用 $jordan1 = &$jordan; 当jordan1 = null; //此时会直接调用析构函数 而当无&时,就需要等到所有的引用都为null时,才调用析构函数析构 乔丹 ...
- 通过unixODBC访问PostgreSQL数据库
磨砺技术珠矶,践行数据之道,追求卓越价值回到上一级页面:PostgreSQL基础知识与基本操作索引页 回到顶级页面:PostgreSQL索引页[作者 高健@博客园 luckyjackgao@g ...
- 【BZOJ2589】[SPOJ10707]Count on a tree II
[BZOJ2589][SPOJ10707]Count on a tree II 题面 bzoj 题解 这题如果不强制在线就是一个很\(sb\)的莫队了,但是它强制在线啊\(qaq\) 所以我们就用到了 ...
- JDBC处理大数据
1.处理大文本 package com.demo; import java.io.File; import java.io.FileNotFoundException; import java.io. ...
- idea scala 报 with UTF-8 Please try specifying another one using the -encoding option
现象如下图, 代码里有汉字,执行代码报错,说编码格式不对, 修改方式如上面,将右下角的编码格式修改成 u8即可.
- Throwable、Error、Exception、RuntimeException的区别与联系
Throwable类是Java语言中所有错误和异常的超类.只有作为此类(或其子类之一)的实例的对象才被Java虚拟机抛出,或者可以被Java throw语句抛出.类似地,只有这个类或其子类之一可以是c ...
- 常用JDBC数据库驱动包和类名
MySQL数据库: 1)驱动包:https://mvnrepository.com/artifact/mysql/mysql-connector-java(下载路径) 2)驱动类名:com.mysql ...
- STC 单片机ADC实现原理
模数转换器原理 数模转换器( analog to digitI converter,ADC),简称为A/D,ADC是链接模拟世界和数字世界的桥梁.它用于将连续的模拟信号转换为数字形式离散信号.典型的, ...
- BZOJ 1901 Zju2112 Dynamic Rankings 树状数组套线段树
题意概述:带修改求区间第k大. 分析: 我们知道不带修改的时候直接上主席树就可以了对吧?两个版本号里面的节点一起走在线段树上二分,复杂度是O((N+M)logN). 然而这里可以修改,主席树显然是凉了 ...
- Python学习之路6 - 装饰器
装饰器 定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能.原则:1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式 实现装饰器的知识储备: 1.函数即“变量” 2.高阶函 ...