BZOJ 4372/3370 烁烁的游戏/震波 (动态点分治+线段树)
烁烁的游戏 题目大意:
给你一棵$n$个节点的树,有$m$次操作,询问某个节点的权值,或者将与某个点$x$距离不超过$d$的所有节点的权值都增加$w$
动态点分裸题
每个节点开一棵权值线段树
对于修改操作,它从$x$开始,像一个涟漪扩散,对它周围与它距离$\leq d$的所有节点造成$w$点贡献
为了记录这个操作的贡献,我们寻找树分治每一层中 包含这个节点的那个点分树的重心$root$
在$root$处记录贡献,开一棵动态开点权值线段树,记录与这个节点距离为$d$的贡献总和,显然在$root$周围扩散范围是$d-dis(x,root)$
还要去掉包含$x$子树的贡献,所以每个节点要再开一个,记录对于父重心需要去掉的贡献
每次查询都沿着点分重心往上跳,因为修改的过程是在线段树上打差分,所以在当前重心查询$d-dis(x,root)$的后缀和即可
由于每次修改都要不断网上跳重心,一共要修改$log$次,每次都要求距离,所以采用欧拉序求$LCA$减小常数
空间是$O(nlog^{2}n)$的,容易被卡,记录当前节点最大能扩散的范围,即当前节点接管的那部分子树内节点的最大深度,非常有效地优化了空间
实在是讲不太明白,大家可以看代码
#include <map>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 101000
#define ll long long
#define dd double
#define inf 0x3f3f3f3f3f3f3f3fll
using namespace std; int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
} struct SEG{
int sum[N1*],ls[N1*],rs[N1*],rm[N1],rf[N1],tot;
void pushup(int rt){sum[rt]=sum[ls[rt]]+sum[rs[rt]];}
void update(int x,int l,int r,int &rt,int w)
{
if(!rt) rt=++tot;
if(l==r) {sum[rt]+=w;return;}
int mid=(l+r)>>;
if(x<=mid) update(x,l,mid,ls[rt],w);
else update(x,mid+,r,rs[rt],w);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(!rt) return ;
if(L<=l&&r<=R) return sum[rt];
int mid=(l+r)>>,ans=;
if(L<=mid) ans+=query(L,R,l,mid,ls[rt]);
if(R>mid) ans+=query(L,R,mid+,r,rs[rt]);
return ans;
}
}s; struct Edge{
int to[N1<<],nxt[N1<<],head[N1],cte;
void ae(int u,int v)
{cte++;to[cte]=v,nxt[cte]=head[u],head[u]=cte;}
}e; int n,m,T;
namespace tr{
int dep[N1],ff[N1<<][],st[N1],id[N1<<],lg[N1<<],tot;
void dfs1(int u,int dad)
{
id[++tot]=u; st[u]=tot; ff[tot][]=u;
for(int j=e.head[u];j;j=e.nxt[j])
{
int v=e.to[j]; if(v==dad) continue;
dep[v]=dep[u]+; dfs1(v,u); id[++tot]=u; ff[tot][]=u;
}
}
void get_st()
{
int i,j;
for(lg[]=,i=;i<=tot;i++) lg[i]=lg[i>>]+;
for(j=;j<=lg[tot];j++)
for(i=;i+(<<j)-<=tot;i++)
ff[i][j]=dep[ ff[i][j-] ]<dep[ ff[i+(<<(j-))][j-] ]?ff[i][j-]:ff[i+(<<(j-))][j-];
}
int dis(int x,int y)
{
int tx=min(st[x],st[y]),ty=max(st[x],st[y]),L=ty-tx+;
int fa=dep[ ff[tx][lg[L]] ]<dep[ ff[ty-(<<lg[L])+][lg[L]] ]?ff[tx][lg[L]]:ff[ty-(<<lg[L])+][lg[L]];
return dep[x]+dep[y]-*dep[fa];
}
void init(){dfs1(,-);get_st();}
}; using tr::dis; int ms[N1],sz[N1],dep[N1],mad[N1],use[N1],fa[N1],tsz,G;
void dfs(int u,int dad,int g)
{
mad[g]=max(mad[g],dep[u]); sz[u]=;
for(int j=e.head[u];j;j=e.nxt[j])
{
int v=e.to[j]; if(v==dad||use[v]) continue;
dep[v]=dep[u]+; dfs(v,u,g); sz[u]+=sz[v];
}
}
void gra(int u,int dad)
{
sz[u]=; ms[u]=;
for(int j=e.head[u];j;j=e.nxt[j])
{
int v=e.to[j]; if(use[v]||v==dad) continue;
gra(v,u); sz[u]+=sz[v]; ms[u]=max(ms[u],sz[v]);
}
ms[u]=max(ms[u],tsz-sz[u]);
if(ms[u]<ms[G]) G=u;
}
void main_dfs(int u)
{
use[u]=; dep[u]=; dfs(u,-,u);
for(int j=e.head[u];j;j=e.nxt[j])
{
int v=e.to[j]; if(use[v]) continue;
G=; tsz=sz[v]; gra(v,-); fa[G]=u;
main_dfs(G);
}
}
void modify(int x,int K,int w)
{
int i,D;
for(i=x;i;i=fa[i])
{
D=dis(x,i);
if(D<=K) s.update(min(mad[i],K-D),,mad[i],s.rm[i],w);
if(!fa[i]) break;
D=dis(x,fa[i]);
if(D<=K) s.update(min(mad[fa[i]],K-D),,mad[fa[i]],s.rf[i],w);
}
}
int query(int x)
{
int i,D,ans=;
for(i=x;i;i=fa[i])
{
D=dis(x,i);
if(D<=mad[i]) ans+=s.query(D,mad[i],,mad[i],s.rm[i]);
if(!fa[i]) break;
D=dis(x,fa[i]);
if(D<=mad[fa[i]]) ans-=s.query(D,mad[fa[i]],,mad[fa[i]],s.rf[i]);
}
return ans;
} int main()
{
scanf("%d%d",&n,&m);
int i,j,x,y,w,ans=;
for(i=;i<n;i++) x=gint(), y=gint(), e.ae(x,y), e.ae(y,x);
tr::init();
ms[]=tsz=n; G=; gra(,-); gra(G,-);
main_dfs(G); char str[];
for(i=;i<=m;i++)
{
scanf("%s",str);
if(str[]=='M'){
x=gint(); y=gint(); w=gint();
modify(x,y,w);
}else{
x=gint();
ans=query(x);
printf("%d\n",ans);
}
}
return ;
}
震波那道题和这道题非常像,只不过是点的修改和子树的查询
但由于我一直被卡常,没脸放代码了qwq
BZOJ 4372/3370 烁烁的游戏/震波 (动态点分治+线段树)的更多相关文章
- BZOJ4372 烁烁的游戏(动态点分治+线段树)
建出点分树,每个节点维护其作为点分树上lca对子树内点的贡献,线段树维护即可,同时另开一个线段树以减掉父亲重复的贡献. #include<iostream> #include<cst ...
- 【bzoj3730】震波 动态点分治+线段树
题目描述 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着时代的发展,城市 ...
- BZOJ3730震波——动态点分治+线段树(点分树套线段树)
题目描述 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着时代的发展,城市 ...
- 【BZOJ4372】烁烁的游戏(动态点分治)
[BZOJ4372]烁烁的游戏(动态点分治) 题面 BZOJ 大意: 每次在一棵书上进行操作 1.将离某个点u的距离不超过d的点的权值加上w 2.询问单点权值 题解 这题和前面那一道震波几乎是一模一样 ...
- 【bzoj4372】烁烁的游戏 动态点分治+线段树
题目描述 给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:Q x:询问x的点权.M x d w:将树上与节点x距离不超过d的节点的点权均加上w. 输入 第一行两个正整数:n,m接下来的n-1 ...
- 【loj6145】「2017 山东三轮集训 Day7」Easy 动态点分治+线段树
题目描述 给你一棵 $n$ 个点的树,边有边权.$m$ 次询问,每次给出 $l$ .$r$ .$x$ ,求 $\text{Min}_{i=l}^r\text{dis}(i,x)$ . $n,m\le ...
- BZOJ4372烁烁的游戏——动态点分治+线段树(点分树套线段树)
题目描述 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距离不超过d的节点各吸引出w只皮皮鼠.皮皮鼠会被 ...
- [bzoj4372] 烁烁的游戏 [动态点分治+线段树+容斥原理]
题面 传送门 思路 观察一下题目,要求的是修改"距离点$u$的距离一定的点权值",那这个就不能用传统的dfs序类算法+线段树维护,因为涉及到向父亲回溯的问题 看到和树上距离相关的东 ...
- bzoj3730 震波 [动态点分治,树状数组]
传送门 思路 如果没有强制在线的话可以离线之后CDQ分治随便搞. 有了强制在线之后--可能可以二维线段树?然而我不会算空间. 然后我们莫名其妙地想到了动态点分治,然后这题就差不多做完了. 点分树有一个 ...
随机推荐
- Flex教程
详细教程: 1.基础知识:一劳永逸的搞定 flex 布局 2.阮一峰的flex教程:flex syntax flex example
- 训练1-H
小明今年3岁了, 现在他已经能够认识100以内的非负整数, 并且能够进行100以内的非负整数的加法计算. 对于大于等于100的整数, 小明仅保留该数的最后两位进行计算, 如果计算结果大于等于100, ...
- MPlayer 开始支持RTSP/RTP流媒体文件
hostzhu点评:MPlayer对流媒体的支持,让大家能更进一步地利用linux来看网络直播,对Linux下多媒体应用的推动作用可以说不可度量. RTSP/RTP streaming support ...
- Java 超类引用子类对象的示例代码
动态方法分配 dynamic method dispatch 一个被重写的方法的调用会在运行时解析,而不是编译时解析 Java 会根据在调用发生时引用的对象的类型来判断所要执行的方法 public c ...
- VR开发2015年终总结
本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/50617605 作者:car ...
- 【hdu 6336】 Matrix from Arrays
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 找个规律会发现 M[i][j] = M[i-2*L][j] = M[i][j-2*L] 先预处理出来(1,1)-(2L,2L)这个矩 ...
- cogs 969. [NOIP2006] 数列
969. [NOIP2006] 数列 ★☆ 输入文件:sequenc.in 输出文件:sequenc.out 简单对比时间限制:1 s 内存限制:162 MB 题目描述 给定一个正整数 ...
- T4系列文章之1:认识T4
一.导读 MSDN:Code Generation and T4 Text Templates 博客园:编写T4模板进行代码生成 Oleg Sych系列文章:http://www.olegsych.c ...
- 解决was6版本号过期问题
原创作品.出自 "深蓝的blog" 博客,欢迎转载.转载时请务必注明出处.否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlong ...
- 在IntelliJ IDEA中创建Maven多模块项目
在IntelliJ IDEA中创建Maven多模块项目 1,创建多模块项目选择File>New>Project 出现New Project窗口左侧导航选择Maven,勾选右侧的Create ...