P6329-[模板]点分树 | 震波
正题
题目链接:https://www.luogu.com.cn/problem/P6329
解题思路
给出\(n\)个点的一棵树,每个点有权值,有\(m\)次操作
- 修改一个点\(x\)的权值为\(y\)
- 询问距离点\(x\)不超过\(k\)的所有点点权和
解题思路
点分树的模板题,先点分治构造出点分树,然后在上面维护信息。
对于每个点维护一个点分子树内,与该点的距离为下标,点权为权值的的树状数组,然后查询的时候直接查距离不超过\(k-dis(now,x)\)的就好了。
发现与点分父节点会有算重的情况,这个时候顺便维护一个以与父节点的距离为下标的树状数组,然后减去重复的答案就好了。
时间复杂度\(O(n\log^2 n)\)。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define lowbit(x) (x&-x)
using namespace std;
const int N=1e5+10,T=18,inf=1e9;
struct node{
int to,next;
}a[N<<1];
int n,m,tot,cnt,num,root,fr,val[N];
int ls[N],f[N<<1][T],rfn[N],dep[N];
int fa[N],siz[N],lg[N<<1],mx;
bool v[N];
struct BIT{
vector<int> t;int n;
void Init(int x)
{x++;t.resize(x);n=x;return;}
void Change(int x,int val){
x++;
while(x<=n){
t[x-1]+=val;
x+=lowbit(x);
}
return;
}
int Ask(int x){
if(x<0)return 0;
int ans=0;x++;
if(x>n)x=n;
while(x){
ans+=t[x-1];
x-=lowbit(x);
}
return ans;
}
}s1[N],s2[N];
void addl(int x,int y){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;return;
}
void dfs(int x,int fa){
dep[x]=dep[fa]+1;
f[++cnt][0]=x;rfn[x]=cnt;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa)continue;
dfs(y,x);f[++cnt][0]=x;
}
return;
}
void groot(int x,int fa){
siz[x]=1;int f=0;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(v[y]||y==fa)continue;
groot(y,x);siz[x]+=siz[y];
f=max(f,siz[y]);
}
f=max(f,num-siz[x]);
if(f<fr)root=x,fr=f;
return;
}
void calc(int x,int fa,int dep){
mx=max(mx,dep);
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa||v[y])continue;
calc(y,x,dep+1);
}
return;
}
void Build(int x,int h){
v[x]=1;int S=num,z=fr;
mx=0;calc(x,x,0);
s1[x].Init(mx);
s2[x].Init(h);
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(v[y])continue;
num=(siz[y]>siz[x])?(S-siz[x]):siz[y];
mx=0;calc(y,x,1);
fr=inf;groot(y,x);y=root;fa[y]=x;
Build(y,mx);
}
return;
}
void Init(){
dfs(1,1);
for(int i=2;i<=cnt;i++)lg[i]=lg[i>>1]+1;
for(int j=1;(1<<j)<=cnt;j++)
for(int i=1;i+(1<<j)-1<=cnt;i++){
int x=f[i][j-1],y=f[i+(1<<j-1)][j-1];
f[i][j]=(dep[x]<dep[y])?x:y;
}
fr=inf;num=n;groot(1,1);
Build(root,0);
return;
}
int LCA(int l,int r){
l=rfn[l];r=rfn[r];
if(l>r)swap(l,r);
int z=lg[r-l+1];
int x=f[l][z],y=f[r-(1<<z)+1][z];
return (dep[x]<dep[y])?x:y;
}
int dis(int x,int y)
{return dep[x]+dep[y]-2*dep[LCA(x,y)];}
void Updata(int x,int val){
int now=x;
while(now){
s1[now].Change(dis(now,x),val);
if(fa[now])s2[now].Change(dis(fa[now],x),val);
now=fa[now];
}
return;
}
int Ask(int x,int k){
int ans=0,now=x;
ans=s1[x].Ask(k);
while(fa[now]){
int d=dis(fa[now],x);
ans+=s1[fa[now]].Ask(k-d);
if(fa[now])ans-=s2[now].Ask(k-d);
now=fa[now];
}
return ans;
}
int main()
{
// freopen("P6329_1.in","r",stdin);
// freopen("data.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&val[i]);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
addl(x,y);addl(y,x);
}
Init();
for(int i=1;i<=n;i++)
Updata(i,val[i]);
int last=0;
while(m--){
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
x^=last;y^=last;
if(op){
Updata(x,y-val[x]);
val[x]=y;
}
else
printf("%d\n",last=Ask(x,y));
}
return 0;
}
P6329-[模板]点分树 | 震波的更多相关文章
- 【题解】P6329 【模板】点分树 | 震波
题外话 (其实模板题没必要在这里水题解的--主要是想说这个qwq) 小常数的快乐.jpg 我也不知道我为啥常数特别小跑得飞快--不加快读就能在 luogu 的最优解上跑到 rank5 ( 说不定深夜提 ...
- 一篇自己都看不懂的点分治&点分树学习笔记
淀粉质点分治可真是个好东西 Part A.点分治 众所周知,树上分治算法有$3$种:点分治.边分治.链分治(最后一个似乎就是树链剖分),它们名字的不同是由于分治方式的不同的.点分治,顾名思义,每一次选 ...
- 线段树练习 3&&P3372 【模板】线段树 1
题目描述 Description 给你N个数,有两种操作: 1:给区间[a,b]的所有数增加X 2:询问区间[a,b]的数的和. 输入描述 Input Description 第一行一个正整数n,接下 ...
- 【洛谷3345_BZOJ3924】[ZJOI2015]幻想乡战略游戏(点分树)
大概有整整一个月没更博客了 -- 4 月为省选爆肝了一个月,最后压线进 B 队,也算给 NOIP2018 翻车到 316 分压线省一这个折磨了五个月的 debuff 画上了一个不算太差的句号.结果省选 ...
- 线段树学习笔记(基础&进阶)(一) | P3372 【模板】线段树 1 题解
什么是线段树 线段树是一棵二叉树,每个结点存储需维护的信息,一般用于处理区间最值.区间和等问题. 线段树的用处 对编号连续的一些点进行修改或者统计操作,修改和统计的复杂度都是 O(log n). 基础 ...
- 洛谷P3372 【模板】线段树 1
P3372 [模板]线段树 1 153通过 525提交 题目提供者HansBug 标签 难度普及+/提高 提交 讨论 题解 最新讨论 [模板]线段树1(AAAAAAAAA- [模板]线段树1 洛谷 ...
- 洛谷P3373 【模板】线段树 2
P3373 [模板]线段树 2 47通过 186提交 题目提供者HansBug 标签 难度提高+/省选- 提交 讨论 题解 最新讨论 为啥WA(TAT) 题目描述 如题,已知一个数列,你需要进行 ...
- hdu 3074 Multiply game(模板级线段树)
离机房关门还有十分钟,这点时间能干些什么?故作沉思地仰望星空,重新捋一下一天的学习进度,或者,砍掉一棵模板级线段树. 纯模板,就是把单点更新,区间求和改为单点更新,区间求积. 1A. #include ...
- Luogu3373【模板】线段树2
P3373[模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第一行 ...
随机推荐
- VMware上安装的Ubuntu不显示全屏解决方法
花费了好一会才把电脑上的Vmware装上,把Ubuntu装到虚拟机上,谁知道Ubuntu不显示全屏,我调了分辨率,奈何Ubuntu里面固定的分辨率没有跟我电脑匹配的,然后开始寻找解决方法,在网上找了很 ...
- Docker运行中文版GitLab
docker-compose.yml version: '3' services: web: image: 'twang2218/gitlab-ce-zh:10.5' restart: always ...
- DLL-创建DLL
动态链接库的创建 fangyukuan 2010.6.20 编写DLL时的函数与一般的函数方法基本一样.但要对库中的函数进行必要的声明,以说明哪些函数是可以导出的,哪些函数是不可以导出的. 把DLL中 ...
- FTP 大文件传输问题 解决
问题描述 将附件上传至FTP服务器,但是当附件过大,其大小为几百兆或1-2G时,会出现上传失败的现象 FTP上传原理解析 这里我们使用的是.Net的FtpWebRequest 创建FtpClient ...
- wpf 的style
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" x ...
- linux中 ~ 表示的是什么目录?
~ 表示代码主目录,也就是当前登录用户的用户目录.比如:我登录用户是chencd ~~ 代表的就是 /home/chen/当然前提是有用户目录,如果没有/home/chen目录的话情况就比较多了.总之 ...
- 交互式查询⼯具Impala
Impala是什么: Impala是Cloudera提供的⼀款开源的针对HDFS和HBASE中的PB级别数据进⾏交互式实时查询(Impala 速度快),Impala是参照⾕歌的新三篇论⽂当中的Drem ...
- 百度云网速慢?普通VIP也限速?用户激励措施太套路?Pandownload被举报?这些统统没关系,我们自己搭建一个私人云盘服务器
前言 前几天醒来后,照例耍手机看新闻.在疫情如此严重的档口,一则小小的新闻引起了我内心小小的波动:Pandownload作者被举报了....心里第一件事就是可惜了我盘上的那N多个T的小电影了,&quo ...
- go语言游戏服务端开发(一)——架构
五邑隐侠,本名关健昌,12年游戏生涯. 本教程以Go语言为例. 网络游戏程序分为客户端和服务端.客户端负责图形渲染.交互和一些简单校验处理,服务端负责业务逻辑处理.数据存储. 我们开发一个游戏de ...
- 六种多线程方法解决UI线程堵塞
http://blog.csdn.net/oyi319/article/details/6851371 一.六种多线程方法 .NET Framework2.0框架提供了至少4种方式实现多线程,它们是& ...