动态点分治
例题:lgP6329 【模板】点分树 | 震波
题意:给你一颗形态固定的树支持两个操作
1.每次问你距离一个节点 \(<=k\)的节点的权值和
2.修改一个节点的权值
sol.首先发现,要是每一个都拿点分治来处理,肯定会T飞
并且发现 点分治都过程重复了很多次
不妨先把点分治 的关系树建出来
发现 至多有logn层
直接在上面跑 就好了
(太久没打 码力题,水平下降严重)
真心调不动
#include<bits/stdc++.h>
#define MAXN 800005
#define INF 0x3f3f3f3f
using namespace std;
int n,m,a[MAXN];
vector<int>G[MAXN],G2[MAXN];
int sz[MAXN],val[MAXN],vis[MAXN],f[MAXN][25],dep[MAXN];
int FA[MAXN];
int lca(int x , int y){
	if(dep[x] < dep[y])swap(x , y);
	int dx = dep[x] - dep[y];
	for(int i = 0 ; i <= 20 ; i++)if(dx & (1 << i))x = f[x][i];
	if(x == y)return x;
	for(int i = 20 ; i >= 0 ; i--)if(f[x][i] != f[y][i])x = f[x][i] , y = f[y][i];
	return f[x][0];
}
int dis(int x , int y){return dep[x] + dep[y] - 2 * dep[lca(x , y)];}
void get_fa(int now , int fa){
	cout<<now<<endl;
	dep[now] = dep[fa] + 1;
	f[now][0] = fa;
	for(auto v : G[now]){
		if(v == fa)continue;
		if(dep[v])continue; 
		get_fa(v , now);
	}
}
void get_sz(int now , int fa){
	sz[now] = 1;
	for(auto v : G[now]){
		if(v == fa)continue;
		if(vis[v])continue;
		get_sz(v , now);
		sz[now] += sz[v];
	}
}
int zx;
void get_zx(int now , int fa , int yl){
	for(auto v : G[now]){
		if(v == fa)continue;
		if(vis[v])continue;
		get_zx(v , now , yl);
		val[now] = max(val[now] , sz[v]);
	}
	val[now] = max(val[now] , sz[yl] - sz[now]);
	if(val[zx] > val[now])zx = now;
}
void solve(int now){
	vis[now] = 1;
	for(auto v : G[now]){
		if(vis[v])continue;
		get_sz(v , now);
		zx = 0;
		get_zx(v , now , v);
		solve(zx);
		G2[now].push_back(zx);
		G2[zx].push_back(now);
	}
}
void dfs_init(int now , int fa){
	FA[now] = fa;
	for(auto v : G2[now]){
		if(v == fa)continue;
		dfs_init(v , now);
	}
}
struct ST{
	int dex,RT[MAXN];
	struct node2{int lc,rc,val;}t[MAXN * 25];
	
	int update(int rt , int l , int r , int x , int y){
		if(!rt)rt = ++dex;
		if(l == r){
			t[rt].val += y;
			return rt;
		}
		int mid = (l + r) >>1;
		if(x <= mid)t[rt].lc = update(t[rt].lc , l , mid , x , y);
		else t[rt].rc = update(t[rt].rc , mid + 1 , r , x , y);
		t[rt].val = t[t[rt].lc].val + t[t[rt].rc].val;
		return rt;
	}
	
	int que(int rt , int l , int r , int x , int y){
		if(!rt)return 0;
		if(x <= l && r <= y)return t[rt].val;
		int mid = (l + r) >> 1;
		return que(t[rt].lc , l , mid , x , y) + que(t[rt].rc , mid + 1 , r , x , y);
	}	
}T0,T1;
int main(){
	freopen("P6329_1.in" , "r" , stdin);
	scanf("%d%d" , &n , &m);int x,y;val[0] = INF;
	for(int i = 1 ; i <= n ; i++)scanf("%d" , &a[i]);
	for(int i = 1 ; i < n ; i++){
		scanf("%d%d" , &x , &y);
		G[x].push_back(y);
		G[y].push_back(x);
	}
	get_fa(1 , 1);
	zx = 0 , get_sz(1 , 1) , get_zx(1 , 1 , 1);
	solve(zx);
	dfs_init(1 , -1);
	for(int j = 1 ; j <= 20 ; j++)
		for(int i = 1 ; i <= n ; i++)
			f[i][j] = f[f[i][j - 1]][j - 1];
	
	for(int i = 1 ; i <= n ; i++){
		int now = i;
		while(now != (-1)){
			T0.RT[now] = T0.update(T0.RT[now] , 0 , n - 1 , dis(now , i) , a[i]);
			if(FA[now] != (-1))T1.RT[now] = T1.update(T1.RT[now] , 0 , n - 1 , dis(FA[now] , i) , a[i]);
			now = FA[now];
		}
	}
	
	int op,k;
	while(m--){
		scanf("%d%d%d" , &op , &x , &y);
		if(op == 0){
			k = y;
			int now = x , zz = 0 , pre = 0;
			while(now != (-1)){
				if(dis(now , x) > k){
					pre = now , now = FA[now];
					continue;
				}
				
				zz = zz + T0.que(T0.RT[now] , 0 , n - 1 , 0 , k - dis(now , x));	
				if(pre)zz = zz - T1.que(T1.RT[pre] , 0 , n - 1 , 0 , k - dis(now , x));
				now = FA[now];
			}
			cout<<zz<<endl;
			
		}
		else{
			
			
			
			
		}
	}
	
	
}
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号