【BZOJ4372】烁烁的游戏 动态树分治+线段树
【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
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
3
6
HINT
数据范围:
n,m<=10^5,|w|<=10^4
注意:w不一定为正整数,因为烁烁可能把皮皮鼠吓傻了。
题解:动态点分治+线段树裸题,每个节点开两棵线段树维护它子树中的以及它的父亲要从它中减去的即可。
注意特判边界的问题。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=100010;
int n,m,tot,ans,cnt,mn,rt;
struct sag
{
int ls,rs,sum;
}s[maxn*150];
int to[maxn<<1],next[maxn<<1],head[maxn],siz[maxn],dep[maxn],pos[maxn],md[20][maxn<<1],fa[maxn],Log[maxn<<1];
int r1[maxn],r2[maxn];
bool vis[maxn];
char str[5];
inline void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
void getrt(int x,int fa)
{
int i,tmp=0;
siz[x]=1;
for(i=head[x];i!=-1;i=next[i]) if(!vis[to[i]]&&to[i]!=fa) getrt(to[i],x),siz[x]+=siz[to[i]],tmp=max(tmp,siz[to[i]]);
tmp=max(tmp,tot-siz[x]);
if(tmp<mn) mn=tmp,rt=x;
}
void solve(int x)
{
vis[x]=1;
for(int i=head[x];i!=-1;i=next[i]) if(!vis[to[i]])
tot=siz[to[i]],mn=1<<30,getrt(to[i],x),fa[rt]=x,solve(rt);
}
void dfs(int x,int fa)
{
md[0][++pos[0]]=dep[x],pos[x]=pos[0];
for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa)
dep[to[i]]=dep[x]+1,dfs(to[i],x),md[0][++pos[0]]=dep[x];
}
inline int getmin(int a,int b)
{
a=pos[a],b=pos[b];
if(a>b) swap(a,b);
int k=Log[b-a+1];
return min(md[k][a],md[k][b-(1<<k)+1]);
}
inline int dis(int a,int b)
{
return dep[a]+dep[b]-2*getmin(a,b);
}
void updata(int l,int r,int &x,int a,int b)
{
if(a<0) return ;
if(!x) x=++tot;
s[x].sum+=b;
if(l==r) return ;
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,s[x].ls,a,b);
else updata(mid+1,r,s[x].rs,a,b);
}
int query(int l,int r,int x,int a,int b)
{
if(!x||(a<=l&&r<=b)) return s[x].sum;
int mid=(l+r)>>1;
if(b<=mid) return query(l,mid,s[x].ls,a,b);
if(a>mid) return query(mid+1,r,s[x].rs,a,b);
return query(l,mid,s[x].ls,a,b)+query(mid+1,r,s[x].rs,a,b);
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
int main()
{
n=rd(),m=rd();
int i,j,x,y,a,b,u;
memset(head,-1,sizeof(head));
for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a);
dfs(1,0),tot=n,mn=1<<30,getrt(1,0),solve(rt),tot=0;
for(j=1;(1<<j)<=2*n-1;j++) for(i=1;i+(1<<j)-1<=2*n-1;i++) md[j][i]=min(md[j-1][i],md[j-1][i+(1<<(j-1))]);
for(i=2;i<=2*n-1;i++) Log[i]=Log[i>>1]+1;
for(i=1;i<=m;i++)
{
scanf("%s",str);
if(str[0]=='Q')
{
u=rd(),ans=0;
for(x=u;x;x=y)
{
y=fa[x];
ans+=query(0,n,r1[x],dis(u,x),n);
if(y) ans-=query(0,n,r2[x],dis(u,y),n);
}
printf("%d\n",ans);
}
else
{
u=rd(),a=rd(),b=rd();
for(x=u;x;x=y)
{
y=fa[x];
updata(0,n,r1[x],min(n,a-dis(u,x)),b);
if(y) updata(0,n,r2[x],min(n,a-dis(u,y)),b);
}
}
}
return 0;
}//7 2 1 2 1 4 1 5 2 3 2 7 5 6 M 1 2 1 Q 2
【BZOJ4372】烁烁的游戏 动态树分治+线段树的更多相关文章
- BZOJ4372烁烁的游戏——动态点分治+线段树(点分树套线段树)
题目描述 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠.皮皮鼠会被 ...
- [bzoj4372] 烁烁的游戏 [动态点分治+线段树+容斥原理]
题面 传送门 思路 观察一下题目,要求的是修改"距离点$u$的距离一定的点权值",那这个就不能用传统的dfs序类算法+线段树维护,因为涉及到向父亲回溯的问题 看到和树上距离相关的东 ...
- [BZOJ4372]烁烁的游戏(动态点分治+线段树)
和[BZOJ3730]震波几乎一样,每个点建两棵线段树分别代表它的管辖范围内以它为LCA的路径的贡献和它对父亲的贡献. 注意点分树上的点的距离在原树上不单调,所以不能有若距离超出限制就break之类的 ...
- 【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,初始树上没有皮皮鼠. 烁烁他每次会跳 ...
- BZOJ4372: 烁烁的游戏(动态点分治)
Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮 ...
- 【loj6145】「2017 山东三轮集训 Day7」Easy 动态点分治+线段树
题目描述 给你一棵 $n$ 个点的树,边有边权.$m$ 次询问,每次给出 $l$ .$r$ .$x$ ,求 $\text{Min}_{i=l}^r\text{dis}(i,x)$ . $n,m\le ...
- 【bzoj3730】震波 动态点分治+线段树
题目描述 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着时代的发展,城市 ...
- UVALive 7148 LRIP【树分治+线段树】
题意就是要求一棵树上的最长不下降序列,同时不下降序列的最小值与最大值不超过D. 做法是树分治+线段树,假设树根是x,y是其当前需要处理的子树,对于子树y,需要处理出两个数组MN,MX,MN[i]表示以 ...
随机推荐
- docker 部署nginx+weblogic集群
測试一段时间.再来报告
- 支持向量机(SVM)(三)-- 最优间隔分类器(optimal margin classifier)
在之前为了寻找最有分类器,我们提出了例如以下优化问题: 在这里我们能够把约束条件改写成例如以下: 首先我们看以下的图示: 非常显然我们能够看出实线是最大间隔超平面,如果×号的是正例,圆圈的是负例.在虚 ...
- 上手并过渡到PHP7(3)——Uniform Variable Syntax到底统一了什么
PHP7 up and running 泊学原文链接泊学实操视频 Uniform Variable Syntax 在PHP 7提出Uniform Variable Syntax之前,我们大多数人可能都 ...
- 关于Unity中的碰撞检测和管理(2D)
创建Unity3D项目和Unity2D项目的区别. 1.3D项目有摄像机和太阳光,2D项目只有摄像机 2.3D项目使用的贴图类型是Texture纹理,2D项目使用的贴图类型是Sprite 2D/UI ...
- 解决只有单引号的Json格式转换成bean问题
objectMapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);单引号类似Json格式:{id:124463277,code:null ...
- 【Java面试题】3 Java的"=="和equals方法究竟有什么区别?简单解释,很清楚
==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符. 如果一个变量指向的数据是对象类型的 ...
- opengl 裁剪平面
原帖地址:http://blog.sina.com.cn/s/blog_5ff6097b0100xqvr.html void glClipPlane(GLenum plane, const GLdou ...
- chrome调试技巧--持续更新
1.开始调试:右键审查元素 2.按钮功能: 调出控制台: 切换开发环境全屏还是嵌入: 清空当前显示: 将压缩 js 文件格式化缩进规整的文件: 3.常用页面功能: 查看.编辑(双击)HTML: 查看选 ...
- [python每日一库]——hotshot
High performance logging profiler 官方文档:http://docs.python.org/2/library/hotshot.html#module-hotshot ...
- GIS-008-ArcGIS JS API 全图
//待服务加载完成后,设置视野范围到全图范围 layer.on('load', function () { var extent = map.getLayer(map.layerIds[0]).ful ...