当前位置:网站首页>Tree difference

Tree difference

2022-06-09 13:01:00 lAWTYl

The difference in the tree

General introduction

  The difference on the tree is almost the same as the ordinary interval difference , It solves the problem of modifying the last query offline for many times ( Don't tell me you can't do array differencing qwq).

  Pre cheese : Multiply the demand L C A LCA LCA、 Normal difference

Point difference

  For example, such a question , Every time you modify a path in the tree , The point weights of all points on this path are added k k k, Finally, query the point weight of a point .

  Consider emulating the difference approach of ordinary arrays , Maintain the differential array for the nodes on the tree c c c, We consider a path ( The starting point and the ending point are s , t s, t s,t) The weight of all points on the plus k k k, So the difference array should change like this :

c [ s ] + = k ,    c [ t ] + = k c [ l c a ( s , t ) ] − = k ,    c [ f [ l c a ( s , t ) ] [ 0 ] ] − = k \begin{aligned} c[s] += k, \; &c[t] += k \\ c[lca(s, t)] -= k, \; c[&f[lca(s, t)][0]] -= k \end{aligned} c[s]+=k,c[lca(s,t)]=k,c[c[t]+=kf[lca(s,t)][0]]=k

  above l c a ( s , t ) lca(s, t) lca(s,t) Express s s s and t t t The latest public ancestor of , f f f An array is a multiplication l c a lca lca Used in f f f, f [ l c a ( s , t ) ] [ 0 ] f[lca(s, t)][0] f[lca(s,t)][0] It means the father of the nearest public ancestor .

  This operation should not be difficult to understand , As long as the formula is listed, it should be I can understand .

  At the last inquiry , We only need to make a subtree sum to get the weight of each point ( Namely d f s dfs dfs Just one more time ).

  Find a problem to practice :luogu3258 Squirrel's new home

#include<bits/stdc++.h>
using namespace std;
#define in read()
#define MAXN 300300
#define MAXM 4 * MAXN

inline int read(){
    
	int x = 0; char c = getchar();
	while(c < '0' or c > '9') c = getchar();
	while('0' <=c and c <= '9'){
    
		x = x * 10 + c - '0'; c = getchar();
	}
	return x;
}

int n = 0;
int a[MAXN] = {
     0 };

int tot = 0;
int first[MAXN] = {
     0 };
int   nxt[MAXM] = {
     0 };
int    to[MAXM] = {
     0 };
int     c[MAXN] = {
     0 };
int   ans[MAXN] = {
     0 };

inline void add(int x, int y){
    
	nxt[++tot] = first[x];
	first[x] = tot; to[tot] = y;
}

int dep[MAXN] = {
     0 };
int f[MAXN][35] = {
     0 };
void prework(int x, int fa){
    
	dep[x] = dep[fa] + 1;
	for(int i = 0; i <= 30; i++) f[x][i + 1] = f[f[x][i]][i];
	for(int e = first[x]; e; e = nxt[e]){
    
		int y = to[e];
		if(y == fa) continue;
		f[y][0] = x;
		prework(y, x);
	}
}

int LCA(int x, int y){
    
	if(dep[x] < dep[y]) swap(x, y);
	for(int i = 30; i >= 0; i--){
    
		if(dep[f[x][i]] >= dep[y]) x = f[x][i];
		if(x == y) return x;
	}
	for(int i = 30; i >= 0; i--)
		if(f[x][i] != f[y][i])
			x = f[x][i], y = f[y][i];
	return f[x][0];
}

void dfs(int x, int fa){
    
	for(int e = first[x]; e; e = nxt[e]){
    
		int y = to[e];
		if(y == fa) continue;
		dfs(y, x);
		c[x] += c[y];
	}
}

int main(){
    
	n = in;
	for(int i = 1; i <= n; i++) a[i] = in;
	for(int i = 1; i < n; i++){
    
		int x = in, y = in;
		add(x, y); add(y, x);
	}
	prework(1, 0);
	for(int i = 1; i < n; i++){
    
		int x = a[i], y = a[i + 1];
		int lca = LCA(x, y);
		c[x]++, c[y]++, c[lca]--, c[f[lca][0]]--;
	}
	dfs(1, 0); c[a[1]]++;
	for(int i = 1; i <= n; i++) cout << c[i] - 1 << '\n';
	return 0;
}

Edge difference

  Consider such a question , One path for each change , All edges on this path are weighted plus 1 1 1. Finally, query the edge weight .

  Record two arrays s u m sum sum and p r e v prev prev. s u m x sum_x sumx Indication point x x x To f a ( x ) fa(x) fa(x) The number of occurrences of this side of . p r e v prev prev Record each point to its father's side .

  Give a path for each operation ( The starting point and the ending point are s , t s, t s,t), That's how we deal with it :

s u m [ s ] + + ,    s u m [ t ] + + s u m [ l c a ( s , t ) ] − = 2 \begin{aligned} sum[s&]++, \; sum[t]++ \\ sum&[lca(s, t)]-=2 \end{aligned} sum[ssum]++,sum[t]++[lca(s,t)]=2

  Then we finished .

  Find another exercise to practice :NOIP2015 transport plan

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define in read()
#define MAXN 300300
#define MAXM 4 * MAXN
#define INFI (int)3e8

inline int read(){
    
	int x = 0; char c = getchar();
	while(c < '0' or c > '9') c = getchar();
	while('0' <= c and c <= '9'){
    
		x = x * 10 + c - '0'; c=  getchar();
	}
	return x;
}

int tot = 0;
int first[MAXN] = {
     0 };
int   nxt[MAXM] = {
     0 };
int    to[MAXM] = {
     0 };
int value[MAXM] = {
     0 };
inline void add(int x, int y, int weight){
    
	nxt[++tot] = first[x];
	first[x] = tot; to[tot] = y;
	value[tot] = weight;
}

int pre[MAXN] = {
     0 };
int dis[MAXN] = {
     0 };
int dep[MAXN] = {
     0 };
int f[MAXN][32] = {
     0 };
void prework(int x, int fa){
    
	dep[x] = dep[fa] + 1;
	for(int i = 0; i <= 30; i++) f[x][i + 1] = f[f[x][i]][i];
	for(int e = first[x]; e; e = nxt[e]){
    
		int y = to[e];
		if(y == fa) continue;
		f[y][0] = x; dis[y] = dis[x] + value[e]; pre[y] = value[e];
		prework(y, x);
	}
}

int LCA(int x, int y){
    
	if(dep[x] < dep[y]) swap(x, y);
	for(int i = 30; i >= 0; i--){
    
		if(dep[f[x][i]] >= dep[y]) x = f[x][i];
		if(x == y) return x;
	}
	for(int i = 30; i >= 0; i--)
		if(f[x][i] != f[y][i])
			x = f[x][i], y = f[y][i];
	return f[x][0];
}

int n = 0; int m = 0;
struct Tedge{
    
	int len;
	int x, y, lca;
	bool operator < (const Tedge &rhs) const {
     return len > rhs.len; }
}edge[MAXM];

int mx = 0; int cnt = 0;
int flag = 0;
int sum[MAXN] = {
     0 };

int judge(int x, int fa, int cnt, int mx){
    
	int num = sum[x];
	for(int e = first[x]; e; e = nxt[e]){
    
		int y = to[e];
		if(y == fa) continue;
		num += judge(y, x, cnt, mx);
	}
	if(num >= cnt and pre[x] >= mx) flag = 1;
	return num;
}

int check(int x){
    
	cnt = mx = flag = 0; memset(sum, 0, sizeof(sum));
	for(int i = 1; i <= m; i++){
    
		if(edge[i].len > x){
    
			sum[edge[i].x]++, sum[edge[i].y]++, sum[edge[i].lca] -= 2;
			cnt++; mx = max(mx, edge[i].len);
		}
	}
	if(cnt == 0) return 1;
	int k = judge(1, 0, cnt, mx - x);
	return flag;
}

signed main(){
    
	n = in; m = in;
	for(int i = 1; i < n; i++){
    
		int x = in, y = in, w = in;
		add(x, y, w); add(y, x, w);
	} prework(1, 0);
// for(int i = 1; i <= n; i++) cout << dis[i] << ' '; puts("");
// for(int i = 1; i <= n; i++) cout << pre[i] << ' '; puts("");
	for(int i = 1; i <= m; i++){
    
		edge[i].x = in; edge[i].y = in;
		edge[i].lca = LCA(edge[i].x, edge[i].y);
		edge[i].len = dis[edge[i].x] + dis[edge[i].y] - 2 * dis[edge[i].lca];
	}
	int l = 0; int r = INFI;
	while(l < r){
    
		int mid = (l + r) >> 1;
		if(check(mid)) r = mid;
		else l = mid + 1;
	}
	cout << l << '\n';
	return 0;
}
原网站

版权声明
本文为[lAWTYl]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/160/202206091212331767.html