http://www.lydsy.com/JudgeOnline/problem.php?id=3730 (题目链接)

题意

  给出一棵树,每个节点又一个权值。两个操作,询问距离节点${x}$不超过${k}$的所有节点的权值和,将节点${x}$的权值修改为${k}$。

Solution

  动态树分治。

  每个重心维护两个树状数组。${t[x][i]}$存重心${x}$的子树中到${parent}$的距离为${i}$的节点的权值和。${c[x][i]}$存重心${x}$的子树中到${x}$的距离为${i}$的节点的权值和。

  修改就是沿着${parent}$往上跳树状数组单点修改。

  查询考虑每次向${x}$的${parent}$跳的时候会重复计算在${x}$中的子树的节点,所以我们跳之前还要减去${x}$子树中到查询点的距离满足条件的点,这就是我们维护${t[x]}$的意义。

细节

  树状数组要用vector,不然空间开不下,吧。。话说为什么我跑了这么久→_→

代码

// bzoj3730
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#include<ctime>
#define LL long long
#define inf 1ll<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=100010;
int head[maxn],tt[maxn],bin[30],a[maxn],par[maxn];
int n,m,K,P; struct edge {int to,next;}e[maxn<<1];
struct BIT {
int l;
vector<int> v;
void push(int x,int val) {
if (l<x+1) v.push_back(val),l++;
else v[x]+=val;
}
int lowbit(int x) {
return x&-x;
}
int sum(int x) {
int s=0;
for (int i=x;i;i-=lowbit(i)) s+=v[i];
return s;
}
void add(int x,int val) {
for (int i=x;i<=l;i+=lowbit(i)) v[i]+=val;
}
void Init() {
for (int i=0;i<l;i++) tt[i+1]=v[i],v[i]=0;
v.push_back(0);
for (int i=1;i<=l;i++) add(i,tt[i]);
}
}c[maxn],t[maxn]; namespace LittleTrick {
int fa[maxn][30],deep[maxn],cnt; void link(int u,int v) {
e[++cnt]=(edge){v,head[u]};head[u]=cnt;
e[++cnt]=(edge){u,head[v]};head[v]=cnt;
}
void dfs(int x) {
for (int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0]) {
fa[e[i].to][0]=x;
deep[e[i].to]=deep[x]+1;
dfs(e[i].to);
}
}
int lca(int x,int y) {
if (deep[x]<deep[y]) swap(x,y);
int t=deep[x]-deep[y];
for (int i=0;bin[i]<=t;i++) if (bin[i]&t) x=fa[x][i];
for (int i=20;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return x==y ? x : fa[x][0];
}
int dis(int x,int y) {
return deep[x]+deep[y]-2*deep[lca(x,y)];
}
}
using namespace LittleTrick; namespace NodeDivide {
int f[maxn],size[maxn],vis[maxn];
int Dargen,sum; void caldargen(int x,int fa) {
f[x]=0;size[x]=1;
for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !vis[e[i].to]) {
caldargen(e[i].to,x);
f[x]=max(f[x],size[e[i].to]);
size[x]+=size[e[i].to];
}
f[x]=max(f[x],sum-size[x]);
if (f[x]<f[Dargen]) Dargen=x;
}
void caldeep(int x,int fa,int p,int op) {
if (op==0) t[p].push(dis(x,par[p]),a[x]);
else c[p].push(dis(x,p),a[x]);
for (int i=head[x];i;i=e[i].next)
if (e[i].to!=fa && !vis[e[i].to]) caldeep(e[i].to,x,p,op);
}
void work(int x) {
vis[x]=1;
caldeep(x,0,x,1);
for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to]) {
Dargen=0;sum=size[e[i].to];
caldargen(e[i].to,x);
par[Dargen]=x;
t[Dargen].push(0,0);
caldeep(e[i].to,x,Dargen,0);
work(Dargen);
}
t[x].Init();c[x].Init();
}
void Init() {
f[Dargen=0]=inf;sum=n;
caldargen(1,0);
t[Dargen].push(0,0);
work(Dargen);
}
}
using namespace NodeDivide; namespace Query {
void modify(int x,int val) {
for (int i=x;i;i=par[i]) {
int d1=dis(x,par[i]),d2=dis(x,i);
c[i].add(d2+1,-a[x]);c[i].add(d2+1,val);
t[i].add(d1+1,-a[x]);t[i].add(d1+1,val);
}
a[x]=val;
}
int query(int x) {
int dx=dis(x,P);
int dp=dis(par[x],P);
int res=dx<=K ? c[x].sum(min(c[x].l,K-dx+1)) : 0;
if (!par[x]) return res;
if (dp<=K) res-=t[x].sum(min(t[x].l,K-dp+1));
return res+query(par[x]);
}
}
using namespace Query; int main() {
bin[0]=1;for (int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int u,v,i=1;i<n;i++) {
scanf("%d%d",&u,&v);
link(u,v);
}
dfs(1);
Init();
int ans=0;
for (int op,i=1;i<=m;i++) {
scanf("%d%d%d",&op,&P,&K);
P^=ans,K^=ans;
if (op==0) printf("%d\n",ans=query(P));
else modify(P,K);
}
return 0;
}

最新文章

  1. 在Eclipse中如何关联spring-framework的文档和源代码
  2. 用JAVA代码实现验证邮箱地址是否符合
  3. java基础-008
  4. 运维人愿意听到的话 vs 不愿意听到的话
  5. 关于get和set访问器以及属性和字段变量的区别问题
  6. &lt;audio&gt;使用2
  7. Python爬虫实战(1):爬取Drupal论坛帖子列表
  8. Java EE (12) -- 系统质量的分类
  9. Git 建立仓库及常用命令速查表
  10. js计算本地时间
  11. silverlight处理gif格式图片
  12. 简单选择排序(Simple Selection Sort)
  13. 20155334 曹翔 《网络对抗》逆向及Bof基础
  14. vue开发环境搭建win10
  15. 310实验室OTL问题
  16. mongoose 操作一直转圈
  17. eclipse中下载maven插件解决办法
  18. VS2015编译器按F6不能够重新生成
  19. 领域模型(DomainModel)与视图模型(ViewModel)
  20. OpenLDAP配置TLS加密传输

热门文章

  1. MATLAB复制图片时边框大的问题
  2. codeforces 1133E K Balanced Teams
  3. HTML(2)普通文本的修饰
  4. c++虚继承与虚函数
  5. CentOS 7 Docker基本特性
  6. PHP性能分析工具xdebug+qcachegrind
  7. java中重要的多线程工具类
  8. 2018年第九届蓝桥杯【C++省赛B组】
  9. servlet基础学习总结
  10. Daily Srum 10.28