HDU4918 Query on the subtree 点分治+树状数组
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 点分治+树状数组的更多相关文章
- 【BZOJ4553】[Tjoi2016&Heoi2016]序列 cdq分治+树状数组
[BZOJ4553][Tjoi2016&Heoi2016]序列 Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值可能 ...
- BZOJ 1176 Mokia CDQ分治+树状数组
1176: [Balkan2007]Mokia Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 1854 Solved: 821[Submit][St ...
- 【bzoj3262】陌上花开 CDQ分治+树状数组
题目描述 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa&g ...
- 【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 ...
- LOJ3146 APIO2019路灯(cdq分治+树状数组)
每个时刻都形成若干段满足段内任意两点可达.将其视为若干正方形.则查询相当于求历史上某点被正方形包含的时刻数量.并且注意到每个时刻只有O(1)个正方形出现或消失,那么求出每个矩形的出现时间和消失时间,就 ...
- BZOJ_3262_陌上花开_CDQ分治+树状数组
BZOJ_3262_陌上花开_CDQ分治+树状数组 Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),用三个整数表示. 现在要对每朵花评级,一朵花的级别是它拥有的 ...
- BZOJ_2253_[2010 Beijing wc]纸箱堆叠 _CDQ分治+树状数组
BZOJ_2253_[2010 Beijing wc]纸箱堆叠 _CDQ分治+树状数组 Description P 工厂是一个生产纸箱的工厂.纸箱生产线在人工输入三个参数 n p a , , 之后, ...
- BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组
BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一 ...
- BZOJ_2225_[Spoj 2371]Another Longest Increasing_CDQ 分治+树状数组
BZOJ_2225_[Spoj 2371]Another Longest Increasing_CDQ 分治+树状数组 Description 给定N个数对(xi, yi),求最长上升子 ...
随机推荐
- 腾讯Techo开发者大会PPT分享
腾讯云年度的开发者大会已经落幕,大会包括1场前沿技术主峰会,18个技术专场,150位海内外技术专家,28个互动展区,8场动手实验室,23小时小程序云开发极限编程,1场数据库诊断大赛. 内容上涵盖了最新 ...
- ubantu14.04安装storm伪分布式
1.安装jdk 安装:sudo apt-get install openjdk-7-jdk 配置: 修改文件 sudo nano /etc/profile , 添加以下内容: 立即执行使之生效: 2. ...
- RHEL7.2 安装Eclipse-oxygen Hadoop开发环境
1 Eclipse-oxygen下载地址 http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/re ...
- Install Elastic stack
1. 安装环境 系统版本:centos 6.9 java版本:1.8.0_181 程序版本:6.6 (整个stack需保持相同的版本) 2. 安装顺序 1 Elasticsearch 2 Kibana ...
- linux终端操作
------------恢复内容开始------------ tab键自动补全 ls列出当前文件目录: 默认是当前目录 “.”代表当前目录 “..”代表父目录 -a显示所有,而隐藏文件的第一字符为点“ ...
- 10分钟学会Python函数基础知识
看完本文大概需要8分钟,看完后,仔细看下代码,认真回一下,函数基本知识就OK了.最好还是把代码敲一下. 一.函数基础 简单地说,一个函数就是一组Python语句的组合,它们可以在程序中运行一次或多次运 ...
- Java中的集合(Set,List,Map)
******************collections类总结*************************** JAVA集合主要分为三种类型: Set(集) List(列表) ...
- CentOS 7 安装 bind 服务 实现内网DNS
目录 安装 配置 服务管理 测试 安装 废话不多说,直接安装 yum install -y bind bind-utils 配置 [root@jenkins named]# rpm -ql bind ...
- AJAX与Django
AJAX 什么是AJAX? AJAX不是JavaScript的规范,它的缩写:Asynchronous JavaScript and XML,意思就是用JavaScript执行异步网络请求.提交任务之 ...
- shell脚本中的逻辑判断、文件目录属性判断、if特殊用法、case判断
7月12日任务 20.5 shell脚本中的逻辑判断20.6 文件目录属性判断20.7 if特殊用法20.8/20.9 case判断 20.5 shell脚本中的逻辑判断 逻辑判断在shell中随处可 ...