树剖学习笔记[待填坑]
树链剖分
树剖求LCA
树链部分
重儿子:父结点的所有儿子中子树结点数目最多的结点
轻儿子:父结点中除重儿子以外的儿子
重边:父结点和重儿子连成的边
轻边:父结点和轻儿子连成的边
重链:由多条重边连接而成的路径
- 整棵树会被剖分成若干条重链
- 轻儿子一定是每条重链的顶点
- 任意一条路径被切分成不超过 条链
$fa[u]\ dep[u]\ son[u]\ sz[u]\ top[u]\ $u所在重链的顶点
- dfs1,处理
- dfs2,处理
- 让两个游标沿着各自的重链向上跳,跳到同一条重链上时,深度较小的那个游标所指向的点,就是
总复杂度n个节点m次查询,
树剖求LCA
原题链接
代码
#include <iostream>
#include <vector>
using namespace std;
const int N = 5e5 + 10;
vector<int>e[N];
int fa[N], dep[N] , sz[N] ;
int son[N],top[N];
int n,m,s;
void dfs1(int u,int father)
{
fa[u] = father , dep[u] = dep[father] + 1,sz[u] = 1;
for (int v:e[u])
{
if(v == father)continue;
dfs1(v,u);
sz[u] += sz[v];//累加路径长
if(sz[son[u]] < sz[v])son[u] = v;//跟换重儿子
}
}
void dfs2(int u,int t)
{
top[u] = t;//记录该重链链头头
if(!son[u])return;//叶节点(无重儿子)返回
dfs2(son[u],t);//搜重儿子
for(int v:e[u]){
if(v == fa[u]||v == son[u])continue;//判重
dfs2(v,v);//搜轻儿子
}
}
int lca(int u,int v){
while(top[u]!=top[v]){//上跳
if(dep[top[u]] < dep[top[v]])swap(u,v);
u = fa[top[u]];
}
return dep[u] < dep[v]?u:v;
}
int main()
{
cin >> n >> m >> s ;
for (int u,v, i = 1 ; i < n ; i ++ )
{
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs1(s,s);
dfs2(s,s);
for (int u,v,i = 1 ; i <= m ; i ++ )
{
scanf("%d%d",&u,&v);
printf("%d\n",lca(u,v));
}
return 0;
}
树上修改与查询
$fa[u]\ dep[u]\ son[u]\ sz[u]\ top[u]\ id[u]\ nw[u]\ $存新编号在书中所对应节点的权值
- 树链剖分
- dfs1,处理
- dfs2,处理
- 线段树维护
映射:原树序列线段树
- 树上修改与查询
时间复杂度
代码
#include <iostream>
using namespace std;
#define lscc lsqq,k
#define rscc rsqq,k
#define lsqq lson,x,y
#define rsqq rson,x,y
#define lson ls,l,mid
#define rson rs,mid+1,r
#define ls p<<1
#define rs p<<1|1
#define mid (l+r>>1)
#define len (r-l+1)
const int N = 2e5 + 10;
int h[N],ne[N<<1],w[N],e[N<<1],idx;
int fa[N],dep[N],sz[N],son[N];
int top[N],id[N],nw[N],cnt,mod;
int sum[N<<2],add[N<<2],res,n,m,root;
inline int read(){
int r=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){r=(r*10)+(ch^48);ch=getchar();} return f*r;
}
void Add(int u,int v){e[++idx]=v,ne[idx]=h[u],h[u]=idx;}
void dfs1(int u,int father){
fa[u]=father,dep[u]=dep[father]+1,sz[u]=1;
for(int i=h[u];i;i=ne[i]){int v=e[i];
if(v == father)continue;
dfs1(v,u); sz[u] += sz[v];
if(sz[son[u]] < sz[v])son[u]=v;
}
}
void dfs2(int u,int t){
top[u]=t,id[u]=++cnt,nw[cnt]=w[u];
if(!son[u])return; dfs2(son[u],t);
for(int i=h[u];i;i=ne[i]){ int v=e[i];
if(v == fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
void update(int p){sum[p]=(sum[ls]+sum[rs])%mod;}
void build(int p,int l,int r){
if(l == r)return sum[p] = nw[l]%mod,void();
build(lson),build(rson); update(p);
}
void pushdown(int p,int l,int r){
add[ls]=(add[p]+add[ls])%mod;add[rs]=(add[p]+add[rs])%mod;
sum[ls]=(sum[ls]+(add[p]*(len-(len>>1))%mod))%mod;
sum[rs]=(sum[rs]+(add[p]*(len>>1)%mod))%mod;
add[p] = 0;
}
int qlink(int p,int l,int r,int x,int y){
if(x<=l&&r<=y){res=(sum[p]+res)%mod;return res;} else
{ if(add[p])pushdown(p,l,r);
if(x<=mid)qlink(lsqq);if(y> mid)qlink(rsqq);
}
}
int change(int p,int l,int r,int x,int y,int k){
if(x<=l&&r<=y){add[p]+=k,sum[p]+=k*len;} else
{ if(add[p])pushdown(p,l,r);
if(x<=mid)change(lscc);if(y> mid)change(rscc);
update(p);
}
}
int qrand(int u,int v){
int ans=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
res = 0;qlink(1,1,n,id[top[u]],id[u]);
ans = (ans+res)%mod; u = fa[top[u]];
}
if(dep[u] > dep[v]) swap(u,v);
res=0;qlink(1,1,n,id[u],id[v]);
ans = (res + ans) % mod;
return ans;
}
int linkchange(int u,int v,int k){
k %= mod;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
change(1,1,n,id[top[u]],id[u],k);
u = fa[top[u]];
}
if(dep[u]>dep[v])swap(u,v);
change(1,1,n,id[u],id[v],k);
}
int qson(int u){res = 0;qlink(1,1,n,id[u],id[u]+sz[u]-1);return res;}
void cson(int u,int k){change(1,1,n,id[u],id[u]+sz[u]-1,k);}
signed main()
{
n=read(),m=read(),root=read(),mod=read();
for(int i=1;i<=n;i++)w[i]=read();
for(int x,y,i=1;i<n;i++){
x = read(),y = read();
Add(x,y);
Add(y,x);
}
dfs1(root,root);
dfs2(root,root);
build(1,1,n);
for (int opt,x,y,z,i=1;i<=m;i++){
opt = read();
if(opt==1){
x=read(),y=read(),z=read();
linkchange(x,y,z);
}
if(opt==2){
x=read(),y=read();
printf("%d\n",qrand(x,y));
}
if(opt==3){
x=read(),z=read();
cson(x,z);
}
if(opt==4){
x=read();
printf("%d\n",qson(x));
}
}
return 0;
}
P3178 [HAOI2015]树上操作
注意树以1为根,数据较大要开(signed万岁)他与上题无差别
#include <iostream>
using namespace std;
#define lscc lsqq,k
#define rscc rsqq,k
#define lsqq lson,x,y
#define rsqq rson,x,y
#define lson ls,l,mid
#define rson rs,mid+1,r
#define ls p<<1
#define rs p<<1|1
#define mid (l+r>>1)
#define len (r-l+1)
#define int long long
const int N = 2e5 + 10;
int h[N],ne[N<<1],w[N],e[N<<1],idx;
int fa[N],dep[N],sz[N],son[N];
int top[N],id[N],nw[N],cnt;
int sum[N<<2],add[N<<2],res,n,m;
inline int read(){
int r=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){r=(r*10)+(ch^48);ch=getchar();} return f*r;
}
void Add(int u,int v){e[++idx]=v,ne[idx]=h[u],h[u]=idx;}
void dfs1(int u,int father){
fa[u]=father,dep[u]=dep[father]+1,sz[u]=1;
for(int i=h[u];i;i=ne[i]){int v=e[i];
if(v == father)continue;
dfs1(v,u); sz[u] += sz[v];
if(sz[son[u]] < sz[v])son[u]=v;
}
}
void dfs2(int u,int t){
top[u]=t,id[u]=++cnt,nw[cnt]=w[u];
if(!son[u])return; dfs2(son[u],t);
for(int i=h[u];i;i=ne[i]){ int v=e[i];
if(v == fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
void update(int p){sum[p]=sum[ls]+sum[rs];}
void build(int p,int l,int r){
if(l == r)return sum[p] = nw[l],void();
build(lson),build(rson); update(p);
}
void pushdown(int p,int l,int r){
add[ls]+=add[p];add[rs]+=add[p];
sum[ls]+=add[p]*(len-(len>>1));
sum[rs]+=add[p]*(len>>1);
add[p] = 0;
}
int qlink(int p,int l,int r,int x,int y){
if(x<=l&&r<=y){res=sum[p]+res;return res;} else
{ if(add[p])pushdown(p,l,r);
if(x<=mid)qlink(lsqq);if(y> mid)qlink(rsqq);
}
}
int change(int p,int l,int r,int x,int y,int k){
if(x<=l&&r<=y){add[p]+=k,sum[p]+=k*len;} else
{ if(add[p])pushdown(p,l,r);
if(x<=mid)change(lscc);
if(y> mid)change(rscc);
update(p);
}
}
void cson(int u,int k){change(1,1,n,id[u],id[u]+sz[u]-1,k);}
void add1(int u,int a){change(1,1,n,id[u],id[u],a);}
int qrand(int u,int v){
int ans=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
res = 0; qlink(1,1,n,id[top[u]],id[u]);
ans += res; u = fa[top[u]];
}
if(dep[u] > dep[v]) swap(u,v);
res=0;qlink(1,1,n,id[u],id[v]);
ans = res + ans;
return ans;
}
signed main()
{
n=read(),m=read();
for(int i=1;i<=n;i++) w[i]=read();
for(int x,y,i=1;i<n;i++){
x = read(),y = read();
Add(x,y);
Add(y,x);
}
dfs1(1,1);
dfs2(1,1);
build(1,1,n);
for (int opt,x,y,z,i=1;i<=m;i++){
opt = read();
if(opt==1){
x=read(),y=read();
add1(x,y);
}
if(opt==2){
x=read(),y=read();
cson(x,y);
}
if(opt==3){
x=read();
printf("%lld\n",qrand(1,x));
}
}
return 0;
}
P2146 [NOI2015] 软件包管理器
题目大意:給出一个以1为根的树,每个节点有1或0两种状态开始时每个节点默认为0,给出个询问。
- 对于
install x
查询从该节点到根有多少个结点权值为0,查询后更新为1 - 查询
uninstall x
该节点为根的子树总权值和,查询后更新为0
#include<bits/stdc++.h>
#define lson ls,l,mid
#define rson rs,mid+1,r
#define ls p<<1
#define rs p<<1|1
#define mid (l+r>>1)
using namespace std;
const int N = 2e5 + 10;
int s[N<<2],a[N<<2],sz[N],son[N],top[N],id[N],fa[N],h[N],ne[N],e[N],dep[N],idx,cnt,n,m;
char op[24];
int read(){
int f=1,x=0;char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}return f*x;
}
void add(int u,int v){e[++idx]=v,ne[idx]=h[u],h[u]=idx;swap(u,v);e[++idx]=v,ne[idx]=h[u],h[u]=idx;}
void dfs1(int u,int fas){
sz[u] = 1,dep[u]=dep[fas]+1,fa[u]=fas;
for(int i=h[u];i;i=ne[i]){
int v=e[i];if(v==fas)continue;
dfs1(v,u); sz[u]+=sz[v];
if(sz[son[u]]<sz[v])son[u]=v;
}
}
void dfs2(int u,int t){
top[u]=t,id[u]=++cnt;
if(!son[u])return; dfs2(son[u],t);
for(int i=h[u];i;i=ne[i]){int v=e[i];
if(v==son[u]||v==fa[u])continue;
dfs2(v,v);
}
}
void pushdown(int p,int l,int r){
a[ls]=a[rs]=a[p];if(!a[p])s[ls]=s[rs]=0;
else s[ls]=mid-l+1,s[rs]=r-mid;a[p]=-1;
}
int get_sum(int p,int l,int r,int x,int y,int w){
if(l>=x&&y>=r){int res=s[p]; a[p]=w; s[p]=w*(r-l+1); return res;}
if(a[p]>=0)pushdown(p,l,r);
int res=0;
if(x<=mid)res += get_sum(lson,x,y,w);
if(y>mid)res +=get_sum(rson,x,y,w);
s[p]=s[ls]+s[rs];
return res;
}
int qsum(int u,int v)
{
int ans=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
ans+=get_sum(1,1,n,id[top[u]],id[u],1);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
ans+=get_sum(1,1,n,id[u],id[v],1);
return ans;
}
int main(){
n=read();
for(int i=2;i<=n;i++)add(read()+1,i);
dfs1(1,-1);
dfs2(1,1);
m=read();memset(s,-1,sizeof (s));
for(int u,ans,i=1;i<=m;i++){
scanf("%s",op);u=read()+1;
if(*op=='i')ans=qsum(u,1),ans=dep[u]-ans;
else ans = get_sum(1,1,n,id[u],id[u]+sz[u]-1,0);
printf("%d\n", ans);
}
}
“风雪越是呼啸,雪莲越是绽放”
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具