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,把周围与他距 ...
随机推荐
- 在Bootstrap开发中解决Tab标签页切换图表显示问题
在做响应式页面的时候,往往需要考虑更多尺寸设备的界面兼容性,一般不能写死像素,以便能够使得界面元素能够根据设备的不同进行动态调整,但往往有时候还是碰到一些问题,如Tab标签第一页面正常显示,但是切换其 ...
- ASP.NET Core MVC四种枚举绑定方式
前言 本节我们来讲讲在ASP.NET Core MVC又为我们提供了哪些方便,之前我们探讨过在ASP.NET MVC中下拉框绑定方式,这节我们来再来重点看看枚举绑定的方式,充分实现你所能想到的场景,满 ...
- Python全栈开发之路 【第一篇】:Python 介绍
本节内容 一.Python介绍 python的创始人为荷兰人——吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本 ...
- koa2实现session的两种方式(基于Redis 和MySQL)
一.基于MySQL的实现方式 这种方式需要安装koa-session-minimal和koa-mysql-session两个依赖. 执行 npm install koa-session-minimal ...
- Python-sys模块-61
sys 模块:和Python解释器打交道的模块 sys模块是与python解释器交互的一个接口 sys.argv 命令行参数List,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退 ...
- atcoderI - Coins ( 概率DP)
I - Coins Time Limit: 2 sec / Memory Limit: 1024 MB Score : 100100 points Problem Statement Let NN b ...
- AQS解析(未完成)
参考:Java并发之AQS详解 同步队列和condition等待队列.获取到锁的线程则处于可运行状态,而未获取到锁的线程则被添加到同步队列中,等待获取到锁的线程释放锁. 一.数据结构 Node sta ...
- Use the Microsoft Symbol for VS and Windbg
快捷方式mklink的远程符号由于所有者权限问题,链接到本地可能造成不能使用, 或每次都需要重新下载, 1.环境变量中没有设置_NT_SYMBOL_PATH的值 2.windbg快捷方式中也没有设置- ...
- 【Python3练习题 010】将一个正整数分解质因数。例如:输入90,打印出90=2*3*3*5。
#参考http://www.cnblogs.com/iderek/p/5959318.html n = num = int(input('请输入一个数字:')) #用num保留初始值 f = [] ...
- js this的含义以及讲解
this关键字是一个非常重要的语法点.毫不夸张地说,不理解它的含义,大部分开发任务都无法完成. 首先,this总是返回一个对象,简单说,就是返回属性或方法“当前”所在的对象. 下面来两个例子来让大家更 ...