题意

给定一棵 \(n\) 个节点的树,每个节点有点权。完成 \(q\) 个操作——操作分两种:修改点 \(x\) 的点权、查询与 \(x\) 距离小于等于 \(d\) 的权值总和。

\(1 \leq n,q \leq 10^5\)

思路

从最简单的情况分析——只有一次查询。当然一遍 \(O(n)\) 的 \(\text{dfs}\) 可以直接写,不过要用点分治写的话,\(\text{solve}\) 函数直接容斥一下就可以了。

如果多个询问呢?其实在回答关于点 \(x\) 的询问时,其实只需要计算管辖 \(x\) 的所有重心的答案。我们只需要将点分治的过程记录下来,查询只查管辖 \(x\) 的重心,就可以在 \(\log n\) 的复杂度内回答一次询问了。

具体的实现每道题略有区别,但具体思路大致相同。别忘了我们是从一次查询作优化,那么我们对于一个点,记录它到重心的距离;对于每个重心开一个数组,表示管辖范围内距离为 \(d\) 的节点权值总和,然后前缀和一下就变成了距离小于等于 \(d\) 的权值总和,由于还有容斥的部分,故符号也要记录。若节点 \(x\) 询问为 \(d\) ,对于某一级重心 \(C\) ,距离为 \(dis\) ,对应前缀和数组 \(A\) ,对应符号为 \(s\ (s\in\{1,-1\})\) ,那么 \(x\) 与 \(C\) 的贡献就是 \(s\cdot A[d-dis]\) 。

而带上修改其实也没什么区别,只要把前缀和换成树状数组,然后每次修改,对于某一级重心 \(C\) ,在树状数组的 \(dis\) 位置做修改即可。

动态点分治就是把点分治的过程用适当容器去维护的算法。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long LL;
using namespace std;
const int N=1e5+5;
template<const int maxn,const int maxm>struct Linked_list
{
int head[maxn],to[maxm],nxt[maxm],tot;
Linked_list(){clear();}
void clear(){memset(head,-1,sizeof(head));tot=0;}
void add(int u,int v){to[++tot]=v,nxt[tot]=head[u],head[u]=tot;}
#define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
struct FenwickTree
{
#define lowbit(x) ((x)&-(x))
vector<int>c;int n;
void build(int _n){c.clear();FOR(i,0,n=_n+1)c.push_back(0);}
void update(int k,int val){for(k++;k<=n;k+=lowbit(k))c[k]+=val;}
int query(int k){int res=0;for(k=min(k+1,n);k>0;k^=lowbit(k))res+=c[k];return res;}
#undef lowbit
};
Linked_list<N,N<<1>G;
FenwickTree FT[N*2];int Fc;
int Fid[N][45],dis[N][45],lv[N];bool sgn[N][45];
int sz[N];bool mark[N];
int pw[N],n,q; void CFS(int u,int f,int tot,int &C,int &Mi)
{
sz[u]=1;int res=0;
EOR(i,G,u)
{
int v=G.to[i];
if(v==f||mark[v])continue;
CFS(v,u,tot,C,Mi);
sz[u]+=sz[v];
res=max(res,sz[v]);
}
res=max(res,tot-sz[u]);
if(res<Mi)C=u,Mi=res;
}
void dfs_init(int u,int f,int D,bool s)
{
Fid[u][++lv[u]]=Fc,dis[u][lv[u]]=D,sgn[u][lv[u]]=s;
EOR(i,G,u)
{
int v=G.to[i];
if(v==f||mark[v])continue;
dfs_init(v,u,D+1,s);
}
}
int dfs_dep(int u,int f,int d)
{
int res=d;
EOR(i,G,u)
{
int v=G.to[i];
if(v==f||mark[v])continue;
res=max(res,dfs_dep(v,u,d+1));
}
return res;
}
void dac(int u,int tot)
{
int Mi=1e9;
CFS(u,0,tot,u,Mi);
mark[u]=1;
FT[++Fc].build(dfs_dep(u,0,0));
dfs_init(u,0,0,1);
EOR(i,G,u)
{
int v=G.to[i];
if(mark[v])continue;
FT[++Fc].build(dfs_dep(v,u,1));
dfs_init(v,u,1,0);
dac(v,sz[u]>sz[v]?sz[v]:tot-sz[u]);
}
} void update(int u,int val)
{
FOR(i,1,lv[u])
{
int v=Fid[u][i],w=dis[u][i];
FT[v].update(w,val);
}
}
int query(int u,int d)
{
int res=0;
FOR(i,1,lv[u])
{
int v=Fid[u][i],w=dis[u][i];bool s=sgn[u][i];
if(s)res+=FT[v].query(d-w);
else res-=FT[v].query(d-w);
}
return res;
} int main()
{
while(~scanf("%d%d",&n,&q))
{
G.clear();
FOR(i,1,n)scanf("%d",&pw[i]);
FOR(i,1,n-1)
{
int u,v;
scanf("%d%d",&u,&v);
G.add(u,v),G.add(v,u);
}
Fc=0;
memset(lv,0,sizeof(lv));
memset(mark,0,sizeof(mark));
dac(1,n);
FOR(i,1,n)update(i,pw[i]);
while(q--)
{
char str[5];int x,y;
scanf("%s%d%d",str,&x,&y);
if(str[0]=='!')
{
update(x,y-pw[x]);
pw[x]=y;
}
else if(str[0]=='?')printf("%d\n",query(x,y));
}
}
return 0;
}

HDU 4918 Query on the subtree(动态点分治+树状数组)的更多相关文章

  1. 【BZOJ-3730】震波 动态点分治 + 树状数组

    3730: 震波 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 626  Solved: 149[Submit][Status][Discuss] D ...

  2. bzoj 4372 烁烁的游戏——动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 和 bzoj 3070 震波 是一个套路.注意区间修改的话,树状数组不能表示 dis ...

  3. bzoj 3730 震波——动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3730 查询一个点可以转化为查询点分树上自己到根的路径上每个点对应范围答案.可用树状数组 f ...

  4. bzoj 4372 烁烁的游戏 —— 动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 本以为和 bzoj3730 一样,可以直接双倍经验了: 但要注意一下,树状数组不能查询 ...

  5. bzoj 3730 震波 —— 动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3730 建点分树,每个点记两个树状数组,存它作为重心管辖的范围内,所有点到它的距离情况和到它在 ...

  6. luogu 5311 [Ynoi2011]D1T3 动态点分治+树状数组

    我这份代码已经奇怪到一定程度了~ 洛谷上一直 $TLE$,但是本地造了几个数据都过了. 简单说一下题解: 先建出来点分树. 对于每一个询问,在点分树中尽可能向上跳祖先,看是否能够处理这个询问. 找到最 ...

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

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

  8. [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)

    [BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...

  9. 【BZOJ 1901】【Zju 2112】 Dynamic Rankings 动态K值 树状数组套主席树模板题

    达神题解传送门:http://blog.csdn.net/dad3zz/article/details/50638360 说一下我对这个模板的理解: 看到这个方法很容易不知所措,因为动态K值需要套树状 ...

随机推荐

  1. array_contains 分析函数使用演示

    Hive中的array_contains函数与SQL中的 in关键字 操作类似,用于判定 包含(array_contains)或不包含(!array_contains)关系.与 in不同的是array ...

  2. JAVA程序测试感受

    上周四下午,我们进行了JAVA测试,心里很慌,在家中只是学习了JAVA程序的输入.输出以及各种数据类型使用而已,王建民老师给我们发了一份JAVA的课前测试样卷,是关于学生信息管理系统的,我们提前从学长 ...

  3. ElasticSearch相关文章推荐

    1. ElasticSearch查询:http://www.cnblogs.com/ljhdo/p/4486978.html 2. Elasticsearch Java API 的使用—多条件查询:h ...

  4. Hinton“深度学习之父”和“神经网络先驱”,新论文Capsule将推翻自己积累了30年的学术成果时

    Hinton“深度学习之父”和“神经网络先驱”,新论文Capsule将推翻自己积累了30年的学术成果时 在论文中,Capsule被Hinton大神定义为这样一组神经元:其活动向量所表示的是特定实体类型 ...

  5. vue之component

    因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data.computed.watch.methods 以及生命周期钩子等.仅有的例外是像 el 这样根实例特有的选 ...

  6. python字符格式化

    使用%格式化字符串 字符串格式化使用格式化操作符即百分号. 在%号的左侧放置一个字符串(格式化字符串),而右侧则放置希望格式化的值. In [17]: name = "wxz" I ...

  7. Python网络编程,粘包、分包问题的解决

    tcp编程中的粘包.分包问题的解决: 参考:https://blog.csdn.net/yannanxiu/article/details/52096465 服务端: #!/bin/env pytho ...

  8. mybatis generator 生成中文注释

    mybatis generator默认生成 的注释太奇葩了,完全不能拿到生产去用,不过幸亏提供了接口可以自己扩展.长话短说,要生成如下的domain, package com.demo.domain; ...

  9. HELLO JAVA!

    从今天开始,我将不定期地更新自己在大学学习到的JAVA知识,欢迎大家一同前来观摩学习,如有纰漏还请多多赐教2018-09-1715:39:14

  10. 02: flask 使用举例

    1.1 项目说明   https://github.com/rickyyangrui/Flask_web_demo1 1.项目文件结构 2.项目主文件 cssmin==0.2.0 Flask==0.1 ...