当前位置:网站首页>【模板】树链剖分 P3384
【模板】树链剖分 P3384
2022-08-09 07:01:00 【swust_fang】
题目链接
//部分转自:https://www.luogu.org/problemnew/solution/P3384
初学树链剖分,感觉这个模板题还是容易理解的,但是实在是码量很大的。
知识点:
- 重儿子:对于每一个非叶子节点,它的儿子中 儿子数量最多的那一个儿子 为该节点的重儿子
- 轻儿子:对于每一个非叶子节点,它的儿子中 非重儿子 的剩下所有儿子即为轻儿子
- 叶子节点没有重儿子也没有轻儿子(因为它没有儿子。。)
- 重边:连接任意两个重儿子的边叫做重边
- 轻边:剩下的即为轻边
- 重链:相邻重边连起来的 连接一条重儿子 的链叫重链
- 对于叶子节点,若其为轻儿子,则有一条以自己为起点的长度为1的链
- 每一条重链以轻儿子为起点
- (太智能了,自己弹出来一张图,

首先是通过两个dfs来将信息进行处理
dfs1()
这个dfs要处理几件事情:
- 标记每个点的深度dep[]
- 标记每个点的父亲fa[]
- 标记每个非叶子节点的子树大小(含它自己)
- 标记每个非叶子节点的重儿子编号son[]
void dfs1(int u,int pre,int dep)
{
f[u]=pre;
d[u]=dep;
size[u]=1;
for(int i=head[u];~i;i=edge[i].p)
{
int v=edge[i].to;
if(v==pre) continue;
dfs1(v,u,dep+1);
size[u]+=size[v];
if(size[v]>size[son[u]])
son[u]=v;
}
}dfs2()
这个dfs2也要预处理几件事情
- 标记每个点的新编号
- 赋值每个点的初始值到新编号上
- 处理每个点所在链的顶端
- 处理每条链
void dfs2(int u,int tp)
{
top[u]=tp;
dfn[u]=++t;
tim[t]=u;
if(son[u]) dfs2(son[u],tp);
for(int i=head[u];~i;i=edge[i].p)
{
int v=edge[i].to;
if(v!=f[u]&&v!=son[u]) dfs2(v,v);
}
}顺序:先处理重儿子再处理轻
大概重要的过程就是这两个了,通过轻重儿子划分(先处理重儿子再处理轻)首先可以将其树形结构转化为线性结构,用于线段树来处理各种的树上信息,但是不同于dfs序直接遍历,树链剖分后的新编号,在大多数询问处理的区间中都是连续区间,其实就是把树拆成各个链,然后优雅(baoli)的求解各种问题。
代码:
//#pragma comment (linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<set>
#include<stack>
#include<vector>
#include<map>
#include<queue>
#include<list>
#include<time.h>
#define myself i,l,r
#define lson i<<1
#define rson i<<1|1
#define Lson i<<1,l,mid
#define Rson i<<1|1,mid+1,r
#define half (l+r)/2
#define lowbit(x) x&(-x)
#define min4(a, b, c, d) min(min(a,b),min(c,d))
#define min3(x, y, z) min(min(x,y),z)
#define max3(x, y, z) max(max(x,y),z)
#define max4(a, b, c, d) max(max(a,b),max(c,d))
#define pii make_pair
#define pr pair<int,int>
//freopen("E://1.in","r",stdin);
//freopen("E://1.out","w",stdout);
typedef unsigned long long ull;
typedef long long ll;
const int inff = 0x3f3f3f3f;
const long long inFF = 9223372036854775807;
const int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
const int mdir[8][2] = {0, 1, 0, -1, 1, 0, -1, 0, 1, 1, -1, 1, 1, -1, -1, -1};
const double eps = 1e-10;
const double PI = acos(-1.0);
const double E = 2.718281828459;
using namespace std;
//const int mod=1e9+7;
const int maxn=2e5+5;
int d[maxn];//深度
int son[maxn];//某点的重儿子
int top[maxn];//该点所在链首
int dfn[maxn];//某件点的时间戳
int tim[maxn];//记录某时间戳对应的节点下标
int a[maxn];//节点初始权值
int size[maxn];//以改点为根的子树个数(包括自己
int f[maxn];//前驱
int head[maxn],sign,t;
int n,root,q,mod;
int tree[maxn<<2],lazy[maxn<<2];
struct node
{
int to,p;
}edge[maxn<<1];
void init()
{
for(int i=0;i<=n;i++) head[i]=-1;
sign=t=0;
}
void add(int u,int v)
{
edge[sign]=node{v,head[u]};
head[u]=sign++;
}
void dfs1(int u,int pre,int dep)
{
f[u]=pre;
d[u]=dep;
size[u]=1;
for(int i=head[u];~i;i=edge[i].p)
{
int v=edge[i].to;
if(v==pre) continue;
dfs1(v,u,dep+1);
size[u]+=size[v];
if(size[v]>size[son[u]])
son[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
dfn[u]=++t;
tim[t]=u;
if(son[u]) dfs2(son[u],tp);
for(int i=head[u];~i;i=edge[i].p)
{
int v=edge[i].to;
if(v!=f[u]&&v!=son[u]) dfs2(v,v);
}
}
void pushup(int i,int l,int r)
{
tree[i]=(tree[lson]+tree[rson])%mod;
}
void pushdown(int i,int l,int r)
{
if(lazy[i])
{
int mid=half;
tree[lson]+=(mid-l+1)*lazy[i];
tree[rson]+=(r-mid)*lazy[i];
lazy[lson]+=lazy[i];
lazy[rson]+=lazy[i];
lazy[i]=0;
}
}
void build(int i,int l,int r)
{
if(l==r)
{
tree[i]=a[tim[l]];
return;
}
int mid=half;
build(Lson);
build(Rson);
pushup(myself);
}
void update(int i,int l,int r,int ql,int qr,int val)
{
if(ql<=l&&qr>=r)
{
tree[i]+=val*(r-l+1);
lazy[i]+=val;
return;
}
int mid=half;
pushdown(myself);
if(qr<=mid) update(Lson,ql,qr,val);
else if(ql>mid) update(Rson,ql,qr,val);
else update(Lson,ql,mid,val),update(Rson,mid+1,qr,val);
pushup(myself);
}
int query(int i,int l,int r,int ql,int qr)
{
if(ql<=l&&qr>=r) return tree[i]%mod;
pushdown(myself);
int mid=half;
if(qr<=mid) return query(Lson,ql,qr);
else if(ql>mid) return query(Rson,ql,qr);
else return query(Lson,ql,mid)+query(Rson,mid+1,qr);
}
void solve1(int x,int y,int val)//把x,y的简单路径给加上val,解释如下
{
while(top[x]!=top[y])
{
if(d[top[x]]<d[top[y]]) swap(x,y);
update(1,1,n,dfn[top[x]],dfn[x],val);
x=f[top[x]];
}
if(d[x]>d[y]) swap(x,y);
update(1,1,n,dfn[x],dfn[y],val);
}
int solve2(int x,int y)
{
int ans=0;
while(top[x]!=top[y])//当两个点不在同一条链上
{
if(d[top[x]]<d[top[y]]) swap(x,y);//把x定义为深度比较深的点,让他往上边跳
ans=(ans+query(1,1,n,dfn[top[x]],dfn[x]))%mod;//ans加上x点到x所在链顶端 这一段区间的点权和
x=f[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
}
if(d[x]>d[y]) swap(x,y);//此时两点就在一条链上了
ans=(ans+query(1,1,n,dfn[x],dfn[y]))%mod;//一条链就直接区间和
return ans;
}
void solve3(int x,int val)//把该点
{
update(1,1,n,dfn[x],dfn[x]+size[x]-1,val);
}
int solve4(int x)
{
return query(1,1,n,dfn[x],dfn[x]+size[x]-1)%mod;
}
int main()
{
// freopen("E://testdata.in","r",stdin);
// freopen("E://1.out","w",stdout);
cin>>n>>q>>root>>mod;
init();
int x,y,op,val;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]=a[i]%mod;
for(int i=1;i<n;i++)
scanf("%d %d",&x,&y),add(x,y),add(y,x);
dfs1(root,0,1);
dfs2(root,root);
build(1,1,n);
while(q--)
{
scanf("%d",&op);
if(op==1) {scanf("%d %d %d",&x,&y,&val);solve1(x,y,val%mod);}
else if(op==2) {scanf("%d %d",&x,&y);printf("%d\n",solve2(x,y));}
else if(op==3) {scanf("%d %d",&x,&val);solve3(x,val%mod);}
else {scanf("%d",&x);printf("%d\n",solve4(x));}
}
}
边栏推荐
猜你喜欢
随机推荐
【报错】Root Cause com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
线程池总结
AD画PCB板教程 20分钟讲清楚操作流程 铺铜 网络标号
sklearn数据预处理
2022.8.8DAY628
【烂笔头】各厂商手机手动抓log
【转载】Deep Learning(深度学习)学习笔记整理
mysql summary
The division principle summary within the collection
rsync:recv_generator: mkdir (in backup) failed:Permission denied (13) |failed to set times on '.'
搭载开源鸿蒙系统的嵌入式XM-RK3568工业互联方案
Rsync常见错误
P7阿里面试题2020.07 之滑动窗算法(阿里云面试)
VS2019 common shortcut keys
多米诺骨牌
Altium designer software commonly used the most complete package library, including schematic library, PCB library and 3D model library
找不到和chrome浏览器版本不同的chromedriver的解决方法
longest substring without repeating characters
字节也开始缩招了...
按图搜索1688商品接口(item_search_img-按图搜索1688商品(拍立淘接口)代码对接教程









