当前位置:网站首页>【Template】Tree Chain Segmentation P3384
【Template】Tree Chain Segmentation P3384
2022-08-09 07:06:00 【swust_fang】
题目链接
//部分转自:https://www.luogu.org/problemnew/solution/P3384
Beginner tree chain division,I feel that this template question is easy to understand,But it's really huge.
知识点:
- 重儿子:对于每一个非叶子节点,among its sons The one with the largest number of sons is the heavy son of this node
- 轻儿子:对于每一个非叶子节点,among its sons non-heavy son All remaining sons are called light sons
- 叶子节点没有重儿子也没有轻儿子(Because it has no son..)
- 重边:An edge connecting any two heavy children is called a heavy edge
- 轻边:The rest is the light edge
- 重链:相邻重边连起来的 连接一条重儿子 的链叫重链
- 对于叶子节点,If it is a light son,Then there is a length with itself as the starting point1的链
- Every heavy chain starts with a light son
- (太智能了,A picture pops up,

The first is through twodfsto process the information
dfs1()
这个dfsThere are a few things to deal with:
- 标记每个点的深度dep[]
- 标记每个点的父亲fa[]
- 标记每个非叶子节点的子树大小(contains itself)
- 标记每个非叶子节点的重儿子编号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()
这个dfs2There are a few things to preprocess as well
- 标记每个点的新编号
- Assign the initial value of each point to the new number
- Process the top of the chain where each point is
- Process each chain
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);
}
}顺序:Deal with the heavy son first and then deal with the light
Probably the most important process is these two,Divided by light and heavy son(Deal with the heavy son first and then deal with the light)First, its tree structure can be converted into a linear structure,Used for line segment trees to handle various on-tree information,但是不同于dfstraverse directly in order,The new number after the tree chain is split,In most query processing intervals are continuous intervals,In fact, it is to split the tree into individual chains,Then elegant(baoli)of solving various problems.
代码:
//#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];//The heavy son of a certain point
int top[maxn];//The point is at the head of the chain
int dfn[maxn];//Timestamp of a point
int tim[maxn];//Record the node subscript corresponding to a timestamp
int a[maxn];//Node initial weight
int size[maxn];//The number of subtrees rooted at the point(包括自己
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,yThe simple path to addval,解释如下
{
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);//把xDefined as a point with a relatively deep depth,Let him jump up
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);//At this point two o'clock is on a chain
ans=(ans+query(1,1,n,dfn[x],dfn[y]))%mod;//A chain is a direct interval sum
return ans;
}
void solve3(int x,int val)//put that point
{
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));}
}
}
边栏推荐
- 2019南昌网络赛 C题,Hello 2019
- 2017icpc沈阳 G Infinite Fraction Path BFS+剪枝
- Lottie系列一:介绍与使用
- vlucas/phpdotenv phpdotenv获取变量内容偶尔出现返回false
- 半导体新能源智能装备整机软件系统方案设计
- (本章节完结)排序第五节——非比较排序(计数排序+基数排序+桶排序)(附有自己的视频讲解)
- P1505 [国家集训队]旅游 树链剖分
- 集合内之部原理总结
- Example of using the cut command
- The maximum validity period of an SSL certificate is 13 months. Is it necessary to apply for multiple years at a time?
猜你喜欢

重要消息丨.NET Core 3.1 将于今年12月13日结束支持

找不到和chrome浏览器版本不同的chromedriver的解决方法

买口罩(0-1背包)

搭载开源鸿蒙系统的嵌入式XM-RK3568工业互联方案

排序第四节——归并排序(附有自己的视频讲解)

长沙学院2022暑假训练赛(一)六级阅读

leetcode 之盛水问题

用tensorflow.keras模块化搭建神经网络模型

SAP ALV data export many of the bugs

虚拟机网卡报错:Bringing up interface eth0: Error: No suitable device found: no device found for connection
随机推荐
car-price-deeplearning-0411
常见的分布式事务解决方案
RK3568商显版开源鸿蒙板卡产品解决方案
Neural Network Optimizer
虚拟机网卡报错:Bringing up interface eth0: Error: No suitable device found: no device found for connection
类和结构体
用tensorflow.keras模块化搭建神经网络模型
Invoker 2019CCPC Qinhuangdao Station I Question Simple DP
日期处理,字符串日期格式转换
tianqf的解题思路
Zero shift of leetcode
JSONObject遍历的时候顺序不一致,导致数据对应出错
The division principle summary within the collection
MUV LUV EXTRA 2019CCPC Qinhuangdao Station J Question KMP
Rsync常见错误
P6 ali machine test of 2020 Fibonacci number
ByteDance Interview Questions: Mirror Binary Tree 2020
集合内之部原理总结
【报错】Root Cause com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
Lottie系列二:高级属性