题目描述

背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠。
题意:
给定一颗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节点的皮皮鼠数量。

样例输入

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

样例输出

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烁烁的游戏——动态点分治+线段树(点分树套线段树)的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. P3345 [ZJOI2015]幻想乡战略游戏 动态点分治

    \(\color{#0066ff}{ 题目描述 }\) 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越 ...

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

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

随机推荐

  1. 快速导入导出Oracle数据demo(sqlldr、UTL_FILE)

    本文演示快速sqlldr导入.UTL_FILE导出Oracle表数据实例 表结构如下,演示数据约112万,可自行准备. create table MemberPointDemo ( MEMBERID ...

  2. Python入门-格式化输出

    需求:将用户的姓名.年龄.工作.爱好 ,然后打印成以下格式: ------------ Info of Tom ------ Name : Tom Age : 22 Job : Teacher Hob ...

  3. 培训班课程课时及费用管理系统V3.0,适合钢琴培训班、艺术培训班等

    联系QQ 564955427. ACM3.02 文件下载                    还有: 预收课时版 特点: 1. 适合主要业务是一对一课程和部分集体课培训的中小培训班(非连锁管理).考 ...

  4. Spring AOP详细介绍

    AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Asp ...

  5. asp.net core发布到linux

    在发布到linux的过程中出现两个问题现在总结一下: 我的虚拟机是安装到本机上面的,所以,应该在虚拟机的设置里面设置端口映射.具体设置如下: 选择vm上方的编辑 在弹出的框中选择VMnet8,点击下方 ...

  6. 深入解读Promise对象

    promise对象初印象: promise对象是异步编程的一种解决方案,传统的方法有回调函数和事件,promise对象是一个容器,保存着未来才会结束的事件的结果 promise对象有两个特点: 1.p ...

  7. findBugs安装

    点击“Help->InstallNew Software”,如下图所示: 2 接着如下图所示: 3 Name”输入“findBugs”,“Location”输入“http://findbugs. ...

  8. [转帖]linux tree命令--显示目录的树形结构

    linux tree命令--显示目录的树形结构    版权声明:iamqilei@qq.com https://blog.csdn.net/u011729865/article/details/533 ...

  9. 《Effective C++》资源管理:条款13-条款17

    条款13:以对象管理资源 为了防止资源泄漏,请使用RAII(Resource Acquisition Is Initialization)对象,在构造函数里面获得资源,在析构函数里面释放资源 auto ...

  10. 组建自己的局域网(可以将PC机实现为服务器)

    最近想要自己组建一个集群,并且可以通过外网访问,查了好些资料,终于成功了! 设备清单:笔记本1:(4g内存,500g硬盘),笔记本2:(12g内存,120g固态硬盘) (笔记本2上装有5台虚拟机,操作 ...