正题

题目链接:https://www.luogu.com.cn/problem/P6329


解题思路

给出\(n\)个点的一棵树,每个点有权值,有\(m\)次操作

  1. 修改一个点\(x\)的权值为\(y\)
  2. 询问距离点\(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;
}

最新文章

  1. 【Android】Eclipse自动编译NDK/JNI的三种方法
  2. Redmine新建问题速度慢
  3. CSS中的常用属性
  4. VIM自动补全插件 - YouCompleteMe--&quot;大神级vim补全插件&quot;
  5. Spring与Struts2整合VS Spring与Spring MVC整合
  6. POJ(2784)Buy or Build
  7. 基于HTTP和TFTP的PXE批量自动化安装Linux系统
  8. javascript计算字符串中出现最多的字符和个数
  9. 怎么在ng-repeat生成的元素上操作dom
  10. 【Zookeeper】源码分析之服务器(四)
  11. IT学习逆袭的新模式,全栈实习生,不8000就业不还实习费
  12. eclipse 下修改Dynamic Web Modulle 的问题
  13. ionic3 对android包进行签名
  14. CSS学习笔记_day3
  15. mybatis sql in not in的使用
  16. 系统更新报错--NO_PUBKEY
  17. A1001. A+B Format
  18. Failed to execute request because the App-Domain could not be created. Error: 0x80070002 系统找不到指定的文件。
  19. http get请求参数拼接
  20. js中常见的内置对象

热门文章

  1. 综合练习——寻找有潜力的bilibili百大UP主(1)
  2. Longhorn,企业级云原生容器分布式存储 - 定制默认设置
  3. 再过五分钟,你就懂 HTTP 2.0 了!
  4. n, n+1, ..., 2n 中的 5 数环初探
  5. 理解ASP.NET Core - [02] Middleware
  6. 为开源项目 go-gin-api 增加后台任务模块
  7. 解决方案-问题001:物理机、虚机等等Linux操作系统/usr/bin目录权限误操作,导致无法切换root
  8. Linux(二)——常用命令
  9. 区间DP的瞎扯淡
  10. MyBatis的多表查询笔记