当前位置:网站首页>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;
}
边栏推荐
猜你喜欢
随机推荐
[STM32] Hal library DAC
安全编码之基于栈的缓冲区溢出
评“开发人员不喜欢低代码和无代码的8个理由”
Drawing arc text in gdi+
用JS压缩上传的图片
使 QComboBox 下拉一个树形结构列表
[interpretation of the appender source code of logback]
GDI+ 中区域的使用
[idea imports gradle project and starts]
【Prometheus summary.observe 方法】
【STM32】GuiLite基于HAL库的移植
Zabbix6.0 new feature GEOMAP map marker can you use it?
【 NativeScript 】
[interpretation of redis underlying mechanism: Linux operating system file descriptor FD]
【leetcode周赛记录】第79场双周赛+第295场周赛记录
微信小程序中实现吸顶效果(流畅、不卡顿)
[STM32] Hal library CRC verification
【IDEA导入Gradle项目,并启动】
Detailed explanation of LP mobile mining system development ecosystem
Handlebars模版引擎用法二








