BZOJ4372烁烁的游戏——动态点分治+线段树(点分树套线段树)
题目描述
背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠。
题意:
给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠。
烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠。皮皮鼠会被烁烁吸引,所以会一直待在节点上不动。
烁烁很好奇,在当前时刻,节点u有多少个他的好朋友---皮皮鼠。
大意:
给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:
Q x:询问x的点权。
M x d w:将树上与节点x距离不超过d的节点的点权均加上w。
输入
第一行两个正整数:n,m
接下来的n-1行,每行三个正整数u,v,代表u,v之间有一条边。
接下来的m行,每行给出上述两种操作中的一种。
输出
对于每个Q操作,输出当前x节点的皮皮鼠数量。
样例输入
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
样例输出
3
6
提示
数据范围:
n,m<=10^5,|w|<=10^4
注意:w不一定为正整数,因为烁烁可能把皮皮鼠吓傻了。
这道题和BZOJ3730很像,重点在于修改。
同样考虑对于单次修改用动态点分治如何修改。
假设修改点为x,增加值为k。
对于分治联通块包含x的分治中心,设这个分治中心距离x为d。
那么需要将这个联通块中与分治中心距离<=d的点的点权都增加k,但与x位于分治中心同一子树中的点这样算不合法且在递归下一层分治中心时会对它们进行修改,所以将这些点的点权都减少k(与上面的增加k抵消)。
因为与分治中心距离相同的点会被同时修改,所以每个点开一棵线段树维护以这个点为分治中心时,联通块中与它距离为各个值的点的点权增加多少。
还要开一棵线段树维护以这个点为分治中心时,联通块中与它在点分树上父节点距离为各个值的点点权减少多少。
修改和查询时都从操作点往根爬并对沿途点修改或统计答案。
但这样是前缀修改、单点查询,对于动态开点线段树不好写,我们差分一下就变成单点修改、后缀查询。
时间复杂度O(nlogn^2)
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mid ((l+r)>>1)
using namespace std;
int n,m;
int dfn;
int num;
int tot;
int cnt;
int rot;
int sum;
int x,y,z;
char ch[3];
int f[100010];
int d[100010];
int s[100010];
int mn[100010];
int lg[200010];
int to[200010];
int mx[100010];
int dep[100010];
int vis[100010];
int head[100010];
int root[100010];
int next[200010];
int size[100010];
int froot[100010];
int g[18][200010];
struct miku
{
int ls,rs,sum;
}tr[10000000];
inline void add(int x,int y)
{
next[++tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void dfs(int x,int fa)
{
g[0][++dfn]=dep[x];
s[x]=dfn;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dep[to[i]]=dep[x]+1;
dfs(to[i],x);
g[0][++dfn]=dep[x];
}
}
}
inline void getroot(int x,int fa)
{
size[x]=1;
mx[x]=0;
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
getroot(to[i],x);
size[x]+=size[to[i]];
mx[x]=max(mx[x],size[to[i]]);
}
}
mx[x]=max(mx[x],num-size[x]);
if(mx[x]<mx[rot])
{
rot=x;
}
}
void find_dep(int x,int fa)
{
d[x]=d[fa]+1;
sum=max(sum,d[x]);
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
find_dep(to[i],x);
}
}
}
inline void partation(int x)
{
vis[x]=1;
sum=0;
find_dep(x,0);
mn[x]=sum;
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]])
{
num=size[to[i]];
rot=0;
getroot(to[i],0);
f[rot]=x;
partation(rot);
}
}
}
inline int lca(int x,int y)
{
x=s[x];
y=s[y];
if(x>y)
{
swap(x,y);
}
int len=lg[y-x+1];
return min(g[len][x],g[len][y-(1<<len)+1]);
}
inline int dis(int x,int y)
{
return dep[x]+dep[y]-(lca(x,y)<<1);
}
inline void insert(int &rt,int l,int r,int k,int x)
{
if(!rt)
{
rt=++cnt;
}
tr[rt].sum+=x;
if(l==r)
{
return ;
}
if(k<=mid)
{
insert(tr[rt].ls,l,mid,k,x);
}
else
{
insert(tr[rt].rs,mid+1,r,k,x);
}
}
inline int query(int rt,int l,int r,int k)
{
if(!rt||k>r)
{
return 0;
}
if(l==r)
{
return tr[rt].sum;
}
if(k<=mid)
{
return tr[tr[rt].rs].sum+query(tr[rt].ls,l,mid,k);
}
else
{
return query(tr[rt].rs,mid+1,r,k);
}
}
inline void change(int x,int k,int val)
{
for(int i=x;i;i=f[i])
{
if(dis(x,i)<=k)
{
insert(root[i],0,mn[i],k-dis(x,i),val);
}
if(f[i]&&dis(x,f[i])<=k)
{
insert(froot[i],0,mn[f[i]],k-dis(x,f[i]),val);
}
}
}
inline int query(int x)
{
int res=0;
for(int i=x;i;i=f[i])
{
res+=query(root[i],0,mn[i],dis(x,i));
if(f[i])
{
res-=query(froot[i],0,mn[f[i]],dis(x,f[i]));
}
}
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1,0);
for(int i=2;i<=dfn;i++)
{
lg[i]=lg[i>>1]+1;
}
for(int j=1;(1<<j)<=dfn;j++)
{
for(int i=1;i+(1<<j)-1<=dfn;i++)
{
g[j][i]=min(g[j-1][i],g[j-1][i+(1<<(j-1))]);
}
}
mx[0]=1<<30;
num=n;
getroot(1,0);
partation(rot);
while(m--)
{
scanf("%s",ch);
if(ch[0]=='M')
{
scanf("%d%d%d",&x,&y,&z);
change(x,y,z);
}
else
{
scanf("%d",&x);
printf("%d\n",query(x));
}
}
}
BZOJ4372烁烁的游戏——动态点分治+线段树(点分树套线段树)的更多相关文章
- [bzoj4372] 烁烁的游戏 [动态点分治+线段树+容斥原理]
题面 传送门 思路 观察一下题目,要求的是修改"距离点$u$的距离一定的点权值",那这个就不能用传统的dfs序类算法+线段树维护,因为涉及到向父亲回溯的问题 看到和树上距离相关的东 ...
- [BZOJ4372]烁烁的游戏(动态点分治+线段树)
和[BZOJ3730]震波几乎一样,每个点建两棵线段树分别代表它的管辖范围内以它为LCA的路径的贡献和它对父亲的贡献. 注意点分树上的点的距离在原树上不单调,所以不能有若距离超出限制就break之类的 ...
- BZOJ4372: 烁烁的游戏(动态点分治)
Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮 ...
- 【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 一样,可以直接双倍经验了: 但要注意一下,树状数组不能查询 ...
- P3345 [ZJOI2015]幻想乡战略游戏 动态点分治
\(\color{#0066ff}{ 题目描述 }\) 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越 ...
- 【BZOJ4372】烁烁的游戏 动态树分治+线段树
[BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距 ...
随机推荐
- lambda从入门到精通
JDK8中包含了许多内建的Java中常用到函数接口,比如Comparator或者Runnable接口,这些接口都增加了@FunctionalInterface注解以便能用在lambda上. name ...
- 吉特日化MES-日化行业原料仓库所见问题汇总
2018年工作主要面向的是日化行业,其中包括日化生产以及日化生产原料仓库,和以往接触到仓库有点不一样在于日化行业原料的特性问题,日化行业的原料基本以粉尘和液体为主. 1. 原料的形态上: 日化行业原料 ...
- javascript状态机及在工作流中的应用
#javascript状态机及在工作流中的应用 ##状态机 什么叫状态机(Finite State Machine),书面上的解释可以自己借助搜索引擎寻找到.通俗地来讲是一个状态定义.查找.切换和事件 ...
- Windows Community Toolkit 4.0 - DataGrid - Part03
概述 在上面一篇 Windows Community Toolkit 4.0 - DataGrid - Part02 中,我们针对 DataGrid 控件的 Utilities 部分做了详细分享.而在 ...
- 自建 Gitlab (邮箱配置、拆分 PostgreSQL、Redis) + 随想
前言 最近折腾了一番自建 gitlab,在此做个记录,供君参考.整个构建过程基于 Docker Swarm(近期有计划将微服务移植到 Kubernetes,但还没倒腾顺手,暂时先沿用旧的方案),主题配 ...
- linux shell中单引号、双引号、反引号、反斜杠的区别
摘自http://www.jb51.net/article/33495.htm 1. 单引号 ( '' ) # grep Susan phonebook Susan Goldberg 403-212- ...
- H5 字体属性补充
04-字体属性补充 abc我是段落 <!DOCTYPE html> <html lang="en"> <head> <meta chars ...
- 软件工程(FZU2015) 助教总结
SE_FZU目录:1 2 3 4 5 6 7 8 9 10 11 12 13 本次构建之法-SE助教工作,和福州大学张老师协作,福大学生基本发挥出了一定水平,在此做个小结. 教师 张老师本身的SE教学 ...
- Golang的类型断言
类型断言即判断一个变量是不是某个类型的实例,这个经常用在判断接口的类型,基本的格式: y, ok := x.(type) 上面的语句用于判断变量x是不是type类型,有两种结果: x是type类型的变 ...
- 简要了解 MySql 5.5/5.6/5.7/8 出现的新特性
MySQL的开发周期 在比较之前,首先提一下MySQL的开发周期. MySQL一个大版本的开发,大致经历如下几个阶段: Feature Development Feature Testing Perf ...