树剖
树链剖分
sb错误
- if(to == son[to]||to == fath[x]) continue;
1.好习惯---代码模块化
namespace ****(变量名){
自己写各种函数
}
2.树链剖分
- 建树存图(略)
- 大法师1
siz--->当前链上有几个点
fath--->父节点
dep--->节点深度
作用:找出重儿子,求出链长,
void dfs(ll x,ll fa){
siz[x] = 1,fath[x] = fa,dep[x] = dep[fa] + 1;
for(ll i = head[x] ; i ; i = e[i].next){
ll to = e[i].to;
if(to==fa) continue;
dfs(to,x),siz[x]+=siz[to];
if(siz[son[x]]<siz[to]) son[x]=to;
}
}
- 大法师2
dfn--->dfs序
pre--->dfs序映射点号
top--->当前链的链顶(根节点)
作用:遍历图找 链
void dfs2(ll x,ll tp){
dfn[x] = ++cnt,pre[cnt] = x,top[x] = tp;
if(son[x]) dfs2(son[x],tp);
for(ll i = head[x]; i; i = e[i].next){
ll to = e[i].to;
if(to == son[x]||to == fath[x]) continue;
dfs2(to,to);
}
}
- LCA
深度低的向上跳,而且是暴跳,直接跳到链顶的父节点直到两个点位于同一个链中,这时候哪个链的深度浅,哪个点就是LCA
ll lca(ll x, ll y){
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) y=fath[top[y]];
else x=fath[top[x]];
}
if(dep[x]>dep[y]) return y;
else return x;
}
- 具体修改不粘代码
线段树中,叶子节点中点号是混乱的,但是dfs序是有序的,叶子节点是按照dfs序进行排列的,也就是说区间修改可以用dfs序来实现
code
#include<iostream>
#include<cstdio>
#define ll long long
#define N 100010
using namespace std;
ll n , m , r , mod;
ll dep[N], siz[N], dfn[N], top[N], a[N], son[N], fath[N], pre[N];
ll read() {
ll s = 0, f = 0;
char ch = getchar();
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
namespace Seg{
#define ls p<<1
#define rs p<<1|1
struct node{
ll len , sum ,add;
}tree[N<<2];
void push_up(ll p ){
tree[p].sum=(tree[ls].sum+tree[rs].sum)%mod;
}
void push_down(ll p){
if(!tree[p].add) return ;
tree[ls].add=(tree[ls].add+tree[p].add)%mod;
tree[rs].add=(tree[rs].add+tree[p].add)%mod;
tree[ls].sum=(tree[ls].sum+(tree[p].add*tree[ls].len)%mod)%mod;
tree[rs].sum=(tree[rs].sum+(tree[p].add*tree[rs].len)%mod)%mod;
tree[p].add=0;
}
void add(ll p , ll l , ll r ,ll L , ll R ,ll val){
if(L<=l&&r<=R){
tree[p].add=(tree[p].add+val)%mod;
tree[p].sum=(tree[p].sum+(val*tree[p].len)%mod)%mod;
return ;
}
push_down(p);
ll mid = (l + r ) >> 1;
if(L<=mid) add(ls,l, mid, L, R, val);
if(mid<R) add(rs,mid+1,r, L, R,val);
push_up(p);
}
void build(ll p , ll l ,ll r){
tree[p].sum=0,tree[p].len=r-l+1,tree[p].add=0;
if(l==r){ tree[p].sum = a[pre[l]] ;return ; }
ll mid= (l + r )>> 1;
build(ls,l ,mid),build(rs,mid+1,r);
push_up(p);
}
ll query(ll p , ll l , ll r, ll L ,ll R){
ll ans=0;
if(L <= l&& r <= R){ return tree[p].sum; }
push_down(p);
ll mid = (l + r) >>1;
if(L <= mid) ans =(ans + query(ls,l, mid, L , R ) % mod) % mod;
if(mid <R ) ans = (ans + query(rs,mid+1,r,L , R )%mod)%mod;
return ans;
}
}
namespace Cut{
struct node{
ll to,next;
}e[N<<1];
ll head[N<<1],nume,cnt=0;
void add_edge(ll from,ll to){
e[++nume].next=head[from];
e[nume].to=to;
head[from]=nume;
}
void dfs(ll x,ll fa){
siz[x] = 1,fath[x] = fa,dep[x] = dep[fa] + 1;
for(ll i = head[x] ; i ; i = e[i].next){
ll to = e[i].to;
if(to==fa) continue;
dfs(to,x),siz[x]+=siz[to];
if(siz[son[x]]<siz[to]) son[x]=to;
}
}
void dfs2(ll x,ll tp){
dfn[x] = ++cnt,pre[cnt] = x,top[x] = tp;
if(son[x]) dfs2(son[x],tp);
for(ll i = head[x]; i; i = e[i].next){
ll to = e[i].to;
if(to == son[x]||to == fath[x]) continue;
dfs2(to,to);
}
}
ll lca(ll x, ll y){
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) y=fath[top[y]];
else x=fath[top[x]];
}
if(dep[x]>dep[y]) return y;
else return x;
}
void change(ll x, ll y,ll val){
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x,y);
Seg::add( 1, 1, n, dfn[top[x]], dfn[x], val);
x = fath[top[x]];
}
if(dfn[x] > dfn[y]) swap( x, y);
Seg::add( 1, 1, n, dfn[x], dfn[y], val);
}
ll ask(ll x, ll y){
ll ans=0;
while(top[x] != top[y]){
if( dep[top[x]] < dep[top[y]]) swap(x,y);
ans = (ans + Seg::query( 1, 1, n, dfn[top[x]], dfn[x]))%mod;
x = fath[top[x]];
}
if(dfn[x] > dfn[y]) swap( x, y);
ans = (ans + Seg::query( 1, 1, n, dfn[x], dfn[y]))%mod;
return ans;
}
}
int main(){
n = read(),m = read(),r = read() , mod = read();
for(ll i = 1 ; i <= n ;i++) a[i] = read();
for(ll i = 1 , u, v ; i <= n-1 ;i++){
u = read() , v= read() ;
Cut::add_edge(u,v),Cut:: add_edge(v,u);
}
Cut::dfs(r,0) , Cut::dfs2(r,r),Seg:: build(1,1,n);
ll tpy,x,y,z;
for(int i = 1 ; i <= m; i++){
tpy = read();
switch(tpy){
case 1 :{
x=read(),y=read(),z=read();
Cut::change(x,y,z);
break;
}
case 2 :{
x = read() , y = read();
printf("%lld\n",Cut::ask(x,y)%mod);
break;
}
case 3 :{
x =read(); z=read();
Seg::add(1,1,n,dfn[x],dfn[x]+siz[x]-1,z);
break;
}
case 4 :{
x =read();
printf("%lld\n",Seg::query(1,1,n,dfn[x],dfn[x]+siz[x]-1)%mod);
break;
}
}
}
return 0;
}
Future never has to do with past time,but present time dose.