bobo has a tree, whose vertices are conveniently labeled by 1,2,…,n. At the very begining, the i-th vertex is assigned with weight w i.

There are q operations. Each operations are of the following 2 types:

Change the weight of vertex v into x (denoted as "! v x"),
Ask the total weight of vertices whose distance are no more than d away from vertex v (denoted as "? v d").

Note that the distance between vertex u and v is the number of edges on the shortest path between them.

InputThe input consists of several tests. For each tests:

The first line contains n,q (1≤n,q≤10 5). The second line contains n integers w 1,w 2,…,w n (0≤w i≤10 4). Each of the following (n - 1) lines contain 2 integers a i,b i denoting an edge between vertices a i and b i (1≤a i,b i≤n). Each of the following q lines contain the operations (1≤v≤n,0≤x≤10 4,0≤d≤n).
OutputFor each tests:

For each queries, a single number denotes the total weight.Sample Input

4 3
1 1 1 1
1 2
2 3
3 4
? 2 1
! 1 0
? 2 1
3 3
1 2 3
1 2
1 3
? 1 0
? 1 1
? 1 2

Sample Output

3
2
1
6
6

题意:给你一棵树,N个点,每个点一个权值,然后Q组操作(共两种),第一种是求导一个节点距离不超过d的所有点的权值和是多少;第二种操作时,修改一个点的权值;
题解:多次进行操作1。此时不能每次都O(NlogN)了,太慢了。我们考虑到对于点分治,树的重心一共有logN层,第一层为整棵树的重心,第二层为第一层重心的子树的重心,以此类推,每次至少分成两个大小差不多的子树,所以
一共有logN层。而且,对于一个点,他最多只属于logN个子树,也就是最多只属于logN个重心。所以我们可以预处理出每个点所属于的重心以及到这些重心的距离,以每个重心建树状数组,每个点按照到重心的距离插入到树状数组中,
然后每次查询到u距离不超过d的点的个数就通过树状数组求前缀和得到。假设一个重心x到u的距离为dis,那么便统计到重心x距离不超过d-dis的点的个数,这个过程我们称之为“借力”,本身能力有限,所以需要借助x的影响力。因为
如果这个重心被u借力了,那么这个重心的子重心一定也被借力,由于相邻被借力的两个重心x、y所统计的点会有重复,所以我们需要去重。去重的话我们就通过对每个节点再开一个v对x的树状数组,这个树状数组的意义为:重心x的子
树v的重心为y时,子树v中每个点到x的距离为下标建立的树状数组。因为重心x与重心y交集的部分,重心x包括的部分重心y一定包括,所以统计的时候减去v对x的树状数组中距x不超过d-dis的点的个数即可。访问u所属与的所有重心,
挨个借力,同时去重,便能得到距离u不超过d的点的个数。因为重心最多logN层,每个树状数组最多N个点,logN复杂度的统计,所以每次查询复杂度O(logN*logN)。我们最多为每个节点开2个树状数组,而且每一层所有树状数组的
大小相加不超过N,所以树状数组的占用空间为O(2NlogN)。
在上面的基础上稍做扩充。预处理的时候插入树状数组的就是该点的权值,查询依旧是统计前缀和。修改点权值的时候,便是和查询一样,在u距重心x距离d的位置在x的树状数组中修改u的权值,同时修改u属于重心x的子树v的v对x的树
状数组中相同位置的值。复杂度和查询一样为O(logN*logN)。
参考代码:
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define mkp make_pair
#define lowbit(x) (x&-x) typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=1e5+;
int n,q,w[maxn];
char op[];
struct MSG{
int id1,id2;
int dep;
} msg[maxn][];
struct Edge{
int v,nxt;
} edge[maxn<<];
int vis[maxn],head[maxn],tot;
int root,siz[maxn],mx[maxn],fa[maxn],S;
int maxfloor[maxn],idn,L[maxn<<],R[maxn<<];
int c[maxn*];
void Init()
{
S=n;idn=;
tot=root=;
memset(c,,sizeof c);
memset(vis,,sizeof vis);
memset(w,,sizeof w);
memset(head,-,sizeof head);
memset(msg,,sizeof msg);
}
void AddEdge(int x,int y)
{
edge[tot].v=y;
edge[tot].nxt=head[x];
head[x]=tot++;
} void Add(int l,int r,int pos,int val)
{
while(pos<r-l)
c[l+pos]+=val,pos+=lowbit(pos);
}
int Sum(int l,int r,int len)
{
if(len<) return ;
if(len>r-l-) len=r-l-;
int res=;
while(len) res+=c[l+len],len-=lowbit(len);
return res;
} void getroot(int u,int fa)
{
siz[u]=;mx[u]=;
for(int i=head[u];~i;i=edge[i].nxt)
{
int v=edge[i].v;
if(vis[v]||v==fa) continue;
getroot(v,u);
siz[u]+=siz[v];
mx[u]=max(mx[u],siz[v]);
}
mx[u]=max(mx[u],S-siz[u]);
if(mx[u]<mx[root]) root=u;
} int getmaxdep(int u,int fa)
{
int res=;
for(int i=head[u];~i;i=edge[i].nxt)
{
int v=edge[i].v;
if(vis[v]||v==fa) continue;
res=max(res,+getmaxdep(v,u));
}
return res;
}
void dfs(int u,int fa,int deep,int id,int flor,int tp)
{
if(!tp) msg[u][flor].id1=id;
else msg[u][flor].id2=id;
msg[u][flor].dep=deep;
Add(L[idn],R[idn],deep,w[u]);
for(int i=head[u];~i;i=edge[i].nxt)
{
int v=edge[i].v;
if(!vis[v]&&v!=fa) dfs(v,u,deep+,id,flor,tp);
}
}
void solve(int u,int s,int flor)
{
vis[u]=; maxfloor[u]=flor;
idn++; L[idn]=R[idn-];
R[idn]=L[idn]+getmaxdep(u,)+;
dfs(u,,,idn,flor,);
msg[u][flor].id2=-;
for(int i=head[u];~i;i=edge[i].nxt)
{
int v=edge[i].v;
if(vis[v]) continue;
idn++;L[idn]=R[idn-];
R[idn]=L[idn]+getmaxdep(v,u)+;
dfs(v,u,,idn,flor,);
} for(int i=head[u];~i;i=edge[i].nxt)
{
int v=edge[i].v;
if(vis[v]) continue;
S=siz[v]; root=;
if(siz[v]>siz[u]) S=s-siz[u];
getroot(v,u);
solve(root,siz[v],flor+);
}
} int main()
{
while(~scanf("%d%d",&n,&q))
{
Init();
for(int i=;i<=n;++i) scanf("%d",w+i);
for(int i=;i<n;++i)
{
int x,y;
scanf("%d%d",&x,&y);
AddEdge(x,y);AddEdge(y,x);
}
mx[root]=INF;
getroot(,);
solve(,S,);
while(q--)
{
int x,y,ans;
scanf("%s%d%d",&op,&x,&y);
if(op[]=='?')
{
ans=;
for(int f=;f<=maxfloor[x];++f)
{
int id1=msg[x][f].id1;
int id2=msg[x][f].id2;
int dep=msg[x][f].dep;
ans+=Sum(L[id1],R[id1],y+-dep);
if(id2!=-) ans-=Sum(L[id2],R[id2],y+-dep);
}
printf("%d\n",ans);
}
else
{
for(int f=;f<=maxfloor[x];++f)
{
int id1=msg[x][f].id1;
int id2=msg[x][f].id2;
int dep=msg[x][f].dep;
Add(L[id1],R[id1],dep,y-w[x]);
if(id2!=-) Add(L[id2],R[id2],dep,y-w[x]);
}
w[x]=y;
}
}
} return ;
}

HDU4918 Query on the subtree 点分治+树状数组的更多相关文章

  1. 【BZOJ4553】[Tjoi2016&Heoi2016]序列 cdq分治+树状数组

    [BZOJ4553][Tjoi2016&Heoi2016]序列 Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值可能 ...

  2. BZOJ 1176 Mokia CDQ分治+树状数组

    1176: [Balkan2007]Mokia Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 1854  Solved: 821[Submit][St ...

  3. 【bzoj3262】陌上花开 CDQ分治+树状数组

    题目描述 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa&g ...

  4. 【bzoj2225】[Spoj 2371]Another Longest Increasing CDQ分治+树状数组

    题目描述 给定N个数对(xi, yi),求最长上升子序列的长度.上升序列定义为{(xi, yi)}满足对i<j有xi<xj且yi<yj. 样例输入 8 1 3 3 2 1 1 4 5 ...

  5. LOJ3146 APIO2019路灯(cdq分治+树状数组)

    每个时刻都形成若干段满足段内任意两点可达.将其视为若干正方形.则查询相当于求历史上某点被正方形包含的时刻数量.并且注意到每个时刻只有O(1)个正方形出现或消失,那么求出每个矩形的出现时间和消失时间,就 ...

  6. BZOJ_3262_陌上花开_CDQ分治+树状数组

    BZOJ_3262_陌上花开_CDQ分治+树状数组 Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),用三个整数表示. 现在要对每朵花评级,一朵花的级别是它拥有的 ...

  7. BZOJ_2253_[2010 Beijing wc]纸箱堆叠 _CDQ分治+树状数组

    BZOJ_2253_[2010 Beijing wc]纸箱堆叠 _CDQ分治+树状数组 Description P 工厂是一个生产纸箱的工厂.纸箱生产线在人工输入三个参数 n p a , , 之后, ...

  8. BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组

    BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一 ...

  9. BZOJ_2225_[Spoj 2371]Another Longest Increasing_CDQ 分治+树状数组

    BZOJ_2225_[Spoj 2371]Another Longest Increasing_CDQ 分治+树状数组 Description        给定N个数对(xi, yi),求最长上升子 ...

随机推荐

  1. linux 设置固定ip和dns

    目录 1. centos 1.1 ifconfig 查看网卡名称 1.2 设置固定ip和dns 1.3 重启网络 2. ubuntu 2.1 ifconfig 查看网卡名称 2.2 设置固定ip和dn ...

  2. Asciinema文章勘误及Web端使用介绍

    欠下的债迟早是要还的,查文档,重验证,出结果,不误导 文章勘误 在上一篇文章Asciinema:你的所有操作都将被录制中有两个地方表述有错误或瑕疵,这里更正一下 第一个地方为录制时的参数--stdin ...

  3. VLAN实验(2)Trunk接口

    1.选择1台S5700.2台S3700和4台pc机,并根据实验编址完成此拓扑图. 2.启动设备,检查设备的连通性: 由于现在我们还没有划分VLAN,这5台PC,还在同一个VLAN中,现在我们启动所有的 ...

  4. python-语言元素

    变量命令 对于每个变量我们需要给它取一个名字.在python中,变量命名需要遵循一下这些必须遵守硬性规则和强烈建议遵守的非硬性规则. 硬性规则 变量名由字母(广义的Unicode字符,不包括特殊字符) ...

  5. svn文件被锁不能提交的解决办法

    记录工作中遇到的问题,分享出来: 前端时间在提交项目到svn遇到一个问题, 提交的时候提示:文件已经锁定!如下图: 原因是我之前提交的时候不小心中途停了,导致文件被锁,然后也没在意那么多, 趁着今天有 ...

  6. webapi跨域使用session

    在之前的项目中,我们设置跨域都是直接在web.config中设置的. 这样是可以实现跨域访问的.因为我们这边一般情况下一个webapi会有多个网站.小程序.微信公众号等访问,所以这样设置是没有问题的. ...

  7. 选择了uniapp开发app

    7月份打算做一简单app,之前公司做app的时候简单用过Dcloud公司的mui,当时由于uniapp刚出来,最终选择了mui.对uniapp的 了解几乎没有. 做app对我来说几乎是零基础的,当然是 ...

  8. python与redis交互及redis基本使用

    Redis简介 Redis是一使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日个开源的志型.Key-Value数据库,并提供多种语言的API. 从2010年3月15日起,Redis的开发工 ...

  9. 架构师成长之路5.2-Saltstack远程执行

    点击架构师成长之路 架构师成长之路5.2-Saltstack远程执行 配置管理工具: Pupper:1. 采用ruby编程语言:2. 安装环境相对较复杂:3.不支持远程执行,需要FUNC工具配置才可以 ...

  10. 是谁,在敲打我窗-CSS雨滴动画效果

    1.扯闲篇 是谁在敲打我窗  是谁在撩动琴弦  那一段被遗忘的时光 渐渐地回升出我心坎  是谁在敲打我窗  是谁在撩动琴弦 记忆中那欢乐的情景  慢慢地浮现在我的脑海 那缓缓飘落的小雨  不停地打在我 ...