题目传送门

题目大意: 有一棵 n n n 个带权点的树,所有边的长度都是 1 1 1,现在有两种操作。操作 1 1 1:询问 x x x 周围与它距离不超过 k k k 的点的权值和(包括自己);操作 $24:修改某点的权值。

题解

考虑使用动态点分治。

对于每一次询问,可以从 x x x 开始沿着点分树向上走,对于每个到达的点(也就是重心),我们可以统计答案,该点能提供的贡献就是深度小于等于 k − d e e p [ x ] k-deep[x] k−deep[x](这里的 x x x 的深度(即 d e e p [ x ] deep[x] deep[x])是相对于该重心而言的)的点的贡献和,但是还要减去与 x x x 同一棵子树内的贡献。

对于每一次修改,我们依然沿着点分树走,沿途修改对于每个重心而言深度为 d e e p [ x ] deep[x] deep[x] 的点的贡献和。

发现对于每个重心,我们有两种操作,一是统计小于等于某深度的点的权值和,一种是修改某深度的点的权值和,发现正是个改点求段操作,于是可以用树状数组愉快的解决~

还有一个坑点,就是在点分树上求解的时候,不能在发现某个时候 k − d e e p [ x ] < 0 k-deep[x]<0 k−deep[x]<0 就停下,不继续向上跳求解。因为在点分树上跳时,是不能保证重心到 x x x 的距离递增的。

具体细节看代码吧:

#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
#define maxn 100010int n,m;
int value[maxn];
struct node{int y,next;};
node e[maxn*2];
int first[maxn];
void buildroad(int x,int y)//建边
{static int len=0;e[++len]=(node){y,first[x]};first[x]=len;
}
struct trarr{//树状数组vector<int> tr;int l;trarr(){tr.clear();tr.push_back(0);l=0;}//这个push_back是用来填充数组的0位置的inline int lowbit(int x){return x&(-x);}void add(int x,int y){for(;x<=l;x+=lowbit(x))tr[x]+=y;}int sum(int x){int ans=0;for(;x>=1;x-=lowbit(x))ans+=tr[x];return ans;}
};
bool v[maxn];
int Size,size[maxn],mson[maxn],root;
void getroot(int x,int fa)//找重心
{size[x]=1;mson[x]=0;for(int i=first[x];i;i=e[i].next){int y=e[i].y;if(v[y]||y==fa)continue;getroot(y,x);size[x]+=size[y];if(size[y]>mson[x])mson[x]=size[y];}if(Size-size[x]>mson[x])mson[x]=Size-size[x];if(mson[x]<mson[root])root=x;
}
vector<int>a[maxn];//a[i][j] : 以i为重心的子树中,深度为j的点的权值的总和
int aa[maxn];//aa[i] : 以i为重心的子树的最大深度
trarr atree[maxn];//用来维护a数组的树状数组
struct wulala{int arr[maxn];};
vector<wulala> dis;//dis[i].arr[j] : 点分治第i层中,点j到重心的距离
//因为在点分治的每一层中,每个点只属于一个重心,所以可以这样表示该层中x到重心的距离
wulala newwulala;
int deepp=0;//点分治层数
void getdis_a(int x,int fa,int tr,int deep,int dep)//统计每个点到重心的距离以及以该重心为根的子树内每个深度内的点权和
{if(deep>aa[tr])aa[tr]++,a[tr].push_back(0);a[tr][deep]+=value[x];dis[dep].arr[x]=deep;for(int i=first[x];i;i=e[i].next){int y=e[i].y;if(y==fa||v[y])continue;getdis_a(y,x,tr,deep+1,dep);}
}
int son[maxn];
map<int,int> s[maxn];//给每个儿子重新编号,s[x][y]表示y是x的第几个儿子
vector< vector<int> >b[maxn];//b[i][j][k] : 以i为重心的子树中,i的第j棵子树中深度为k的点权和,此时的深度
vector<int> bb[maxn];//以x为重心的子树中,x的第y棵子树的深度
vector<trarr> btree[maxn];//维护b的树状数组
vector<int> newvec;
void getdis_b(int x,int fa,int tr,int num,int deep)
{if(deep>bb[tr][num])bb[tr][num]++,b[tr][num].push_back(0);b[tr][num][deep]+=value[x];for(int i=first[x];i;i=e[i].next){int y=e[i].y;if(y==fa||v[y])continue;getdis_b(y,x,tr,num,deep+1);}
}
int fa[maxn],con[maxn];
int deep_focus[maxn];//每个重心在点分树中的深度
void buildtree(int x,int deep,int ssize)
{if(deep>deepp)deepp++,dis.push_back(newwulala);v[x]=true;deep_focus[x]=deep;getdis_a(x,0,x,0,deep);for(int i=first[x];i;i=e[i].next){int y=e[i].y;if(v[y])continue;son[x]++;//x的儿子数量s[x][y]=son[x];b[x].push_back(newvec);bb[x].push_back(-1);//注意,是-1不是0,结合上面代码就能理解了getdis_b(y,x,x,son[x],0);root=0;Size=size[y]<size[x]?size[y]:(ssize-size[x]);getroot(y,0);fa[root]=x;con[root]=y;//fa表示root的父亲(在点分树中),con表示root在fa[root]的哪一个儿子的子树中(这个儿子是指原树中的)buildtree(root,deep+1,(size[y]<size[x]?size[y]:(ssize-size[x])));}
}
void buildatree()//将a数组用树状数组atree维护起来
{for(int i=1;i<=n;i++){for(int j=1;j<=aa[i];j++)atree[i].tr.push_back(0);atree[i].l=aa[i];for(int j=1;j<=aa[i];j++)atree[i].add(j,a[i][j]);}
}
trarr newtr;
void buildbtree()//将b数组用树状数组btree维护起来
{for(int i=1;i<=n;i++){btree[i].push_back(newtr);for(int j=1;j<=son[i];j++){btree[i].push_back(newtr);for(int k=1;k<=bb[i][j];k++)btree[i][j].tr.push_back(0);btree[i][j].l=bb[i][j];for(int k=1;k<=bb[i][j];k++)btree[i][j].add(k,b[i][j][k]);}}
}
int last=0;
void work(int x,int dist){ last+=atree[x].sum(min(dist,aa[x]))+a[x][0]; }
//work统计在以x为重心的子树中,与x的距离小于等于dist的点权和
void go(int x,int y,int dist,int point)//统计以在以x为重心的子树中,与point的距离小于等于dist的点权和
//y表示 point在x的y这个儿子的子树中
{int need=dist-dis[deep_focus[x]].arr[point];//need表示将要求以x为重心的子树中深度小于等于need的点权和if(need>=0)//如果小于0则不能产生贡献{last+=atree[x].sum(min(aa[x],need))+a[x][0];//求出点权和last-=btree[x][s[x][y]].sum(min(need-1,bb[x][s[x][y]]))+(need>0?b[x][s[x][y]][0]:0);//减去以y为根的子树产生的贡献//因为0这个位置是不能用树状数组维护的,于是我们单独考虑,change函数中同理}if(fa[x])go(fa[x],con[x],dist,point);
}
void change(int x,int y,int newval,int point)//newval表示point这个节点的新权值
{atree[x].add(dis[deep_focus[x]].arr[point],-value[point]);//减去原来的权值atree[x].add(dis[deep_focus[x]].arr[point],newval);//加上现在的权值if(dis[deep_focus[x]].arr[point]==1)b[x][s[x][y]][0]=newval;//单独考虑0位置else btree[x][s[x][y]].add(dis[deep_focus[x]].arr[point]-1,-value[point]),btree[x][s[x][y]].add(dis[deep_focus[x]].arr[point]-1,newval);if(fa[x])change(fa[x],con[x],newval,point);
}
//--------------------------------------------------------------
//以下为输入输出优化(不卡卡常过不了= =)
inline char cn()
{static char buf[1000010],*t1=buf,*t2=buf;return t1==t2&&(t2=(t1=buf)+fread(buf,1,1000000,stdin),t1==t2)?EOF:*t1++;
}
void read(int &x)
{x=0;char ch=cn();while(ch<'0'||ch>'9')ch=cn();while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=cn();
}
char buff[1000020];
int len=-1;
int output[20],lo;
void add(int x)
{lo=0;while(x>0)output[++lo]=x%10,x/=10;while(lo>0)buff[++len]=output[lo--]+'0';buff[++len]='\n';if(len>1000000)fwrite(buff,1,len,stdout),len=-1;
}
//--------------------------------------------------------------int main()//主函数就没什么好讲的了,其中包含的函数的意义已经讲明白了(其实只是因为懒。。)
{//  freopen("data.txt","r",stdin);
//  freopen("mine.txt","w",stdout);read(n);read(m);for(int i=1;i<=n;i++)read(value[i]);for(int i=1;i<n;i++){int x,y;read(x);read(y);buildroad(x,y);buildroad(y,x);}root=0;Size=n;mson[0]=999999999;memset(aa,-1,sizeof(aa));for(int i=1;i<=n;i++)b[i].push_back(newvec),bb[i].push_back(0);getroot(1,0);dis.push_back(newwulala);buildtree(root,1,n);buildatree();buildbtree();for(int i=1;i<=m;i++){int id,x,y;read(id);read(x);read(y);x^=last,y^=last;if(id==0){last=0;work(x,y);if(fa[x])go(fa[x],con[x],y,x);add(last);}else{a[x][0]=y;if(fa[x])change(fa[x],con[x],y,x);value[x]=y;}}fwrite(buff,1,len,stdout);
}

BZOJ 3070 震波 题解相关推荐

  1. Bzoj 3730 震波 动态点分治

    Bzoj 3730 震波 题解: 和在线的边分治差不多. 就是将每层都信息都存下来. 然后对于每一层记录上一层的重心是哪个. 对于求和的话, 从自己的那层出发,然后暴力往上爬, 然后计算答案. 对于修 ...

  2. 【业界偷懒】【Public】BZOJ题目一句话题解整理

    转发[Hzwer]: 就当是复习一下自己做过的题,顺便提供一个简要题解给大家看. 做题时候实在想不出来看一下一句话题解,可以有一个提示的作用又不至于一下子知道了全部浪费了一道题吧.. 部分题目(如我A ...

  3. 【醒目】【业界偷懒】【Public】BZOJ题目一句话题解整理

    就当是复习一下自己做过的题,顺便提供一个简要题解给大家看. 做题时候实在想不出来看一下一句话题解,可以有一个提示的作用又不至于一下子知道了全部浪费了一道题吧.. 部分题目(如我A过得大部分奶牛题)是别 ...

  4. Bzoj 2064 分裂 题解

    2064: 分裂 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 570  Solved: 350 [Submit][Status][Discuss] ...

  5. [BZOJ 3730] 震波

    BZOJ传送门 题目描述 在一片土地上有NNN个城市,通过N−1" role="presentation" style="position: relative; ...

  6. BZOJ 3730: 震波 动态树分治 线段树 lca

    3730: 震波 Time Limit: 15 Sec  Memory Limit: 256 MB Submit: 1202  Solved: 288 [Submit][Status][Discuss ...

  7. bzoj 3730: 震波 动态点分治+树链剖分+线段树

    ##### 题目描述 : 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]. 不幸的是,这片土地常常发生地震,并且随 ...

  8. BZOJ 4551树题解

    好吧,洛谷的数据比较水暴力就可以过....(而且跑到飞快) 不过(BZ水不过去)还是讲讲正规的做法. 其实一眼可以看出可以树剖,但是,码起来有点麻烦. 其实有一种更简单的离线做法. 我们很容易联想到并 ...

  9. bzoj 4398 福慧双修 题解

    卡了一晚上啊 首先我们要跑一边整张图的spfa,记录每个点是从哪条边出去的(pre数组) 这里记录的不是前驱边,而是和原点相连的第一个点编号,因为不能走重复边所以才要记录这个,以免刚刚出去又原路返回 ...

最新文章

  1. linux shell概述,Linux学习 -- Shell基础 -- 概述
  2. R语言实战应用精讲50篇(八)-随机区组设计资料的方差分析
  3. 4.5. Rspamd
  4. 微信连接WIFI并关注公众号的方法
  5. django select option拼接时value中空格后的内容被截断
  6. slqite3库查询数据处理方式_绝活!十一个优质React Hook库, 收藏备用
  7. Windows YII2安装
  8. 为什么我选择使用 OpenBSD?
  9. 知识付费的时代,我们如何应对:这8个干货,免费送给你!
  10. python读取图像属性并显示_图像读取和显示(Python实现),Opencv,基础,之
  11. lightbox使用_如何使用CSS和JavaScript创建Lightbox Ultra
  12. safari java 插件_精通Safari – 如何在 Mac 版 Safari 中使用互联网插件
  13. 改善客户服务体验的 5 种方法
  14. TextView 的 StaticLayout,比你想象中复杂点!
  15. 单元格中公式结果为0如何不显示0符号?
  16. 服务器就是一台性能好的电脑吗,科普:什么是服务器? 服务器与普通电脑有何区别?...
  17. 今天差点就被黑中介给骗了!!!!!!后怕中。。。
  18. 工作笔记:如何用Django连接Kerberized甲骨文(Oracle)数据库
  19. 推荐一款很好用的一款扒网站的工具
  20. 【计算机专业毕设之基于python猫咪网爬虫大数据可视化分析系统-哔哩哔哩】 https://b23.tv/jRN6MVh

热门文章

  1. 55.EasyCountDownTextureView
  2. 漏洞扫描工具大全,妈妈再也不用担心我挖不到漏洞了
  3. 我的一次华为虚拟化搭建记录:(一)、关于华为虚拟化的架构
  4. spring security导致登录后从https跳转至http解决方案
  5. 查询MySQL的serverId
  6. 使用Java实现3DES加密解密
  7. DVD视频尺寸(720*480)
  8. 灵敏度分享码显示服务器不可用,和平精英灵敏度怎么调 S12最稳灵敏度分享码一览...
  9. MUI框架之移动端前端开发对dialog与button轮播的深入运用与实战
  10. Python为何被其父亲抛弃?