树剖

树链剖分

题目传送门

sb错误

  1. 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;
}

posted @ 2020-11-01 21:33  Imy_bisLy  阅读(186)  评论(4编辑  收藏  举报