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分治随便搞. 有了强制在线之后--可能可以二维线段树?然而我不会算空间. 然后我们莫名其妙地想到了动态点分治,然后这题就差不多做完了. 点分树有一个 ...
随机推荐
- Python docs
刚刚发现了Python好用的文档查询网页:Python docs,可以选择python版本查询,跟OpenCV docs很相似,很好用-
- 工具-docker01
- clipper库使用的一些心得
clipper sourceforge官网:http://sourceforge.net/projects/polyclipping/ 1. 版本号差异 之前project里面使用4.8.6,近期升级 ...
- iOS开发之autoLayout constraint
前言 ios设备的尺寸越来越多,针对一款app可能要适配到多种设备.多种尺寸.所以.我们期望我们的app可以autoLayout.本文主要介绍在Xcode中使用constraint.未来会不定期对此文 ...
- C#创建PDF文档
说明:本实例用到了第三方组件ICSharpCode.SharpZipLib.dll.itextsharp.dll,该组件可到网上下载. 代码: using System; using System.C ...
- Ruby学习笔记(二)——从管道读取数据
在对文件名修改后,今天又给自己出了新的难题,想从实验结果中提取数据,并将其作为文件夹的名称.其中,比赛的主办方提供的评估算法是用perl写的,因此读取实验结果最为简单的想法自然是使用管道命令,即 ./ ...
- js 回调函数小例子
js 回调函数小例子 <script> //将函数作为另一个函数的参数 function test1(){ alert("我是test1"); } function t ...
- oracle init.ora常用配置详解
参考网上整理了重要的配置文件 db_name = "51cto" 一个数据库标识符,应与CREATE DATABASE 语句中指定的名称相对应. instance_name = ...
- Redis学习笔记(六) 基本命令:List操作
原文链接:http://doc.redisfans.com/list/index.html lpush key value[value...] 将一个或多个value插入到列表的表头:例:lpush ...
- Spark Streaming概念学习系列之SparkStreaming的高层抽象DStream
不多说,直接上干货! SparkStreaming的高层抽象DStream 为了便于理解,Spark Streaming提出了DStream抽象,代表连续不断的数据流. DStream 是一个持续的R ...