共计 2275 个字符,预计需要花费 6 分钟才能阅读完成。
什么是差分?
定义 :差分就是数组中每一项都与前一项做差,最初得出的序列。
例如:数组:2,5,3,7,2,3
差分后的序列:2,3,-2,4,-5,1,-3
留神 :第一个数与原数组雷同,相当于 2 -0;最初一个数与原数组互为相反数,相当于 0 -3;
差分的性质 :
1. 差分序列的前缀和就是原数组;
2. 将原数组在[L,R] 区间上的数全副加 1,相当于让差分数组在 L 处 +1,在 R + 1 处 -1;
树上差分
思考差分的一个利用:
图片起源:https://blog.csdn.net/a135193…
树上差分的两种思路:
1. 找被所有门路独特笼罩的边。
例题:洛谷:https://www.luogu.com.cn/prob…
剖析见代码:
//1. 找被所有门路独特笼罩的边。#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <vector>
using namespace std;
const int N = 300010;
int fa[N][26];
int depth[N], dist[N];
int tmp[N], pre[N];
int cnt,flag;
//tmp 存节点呈现的次数,即节点与节点父亲的边在所有门路中呈现的次数
//pre 存节点与节点父亲之间的边,本题中存的是边权,别的题中也有可能存编号
int n, m;
struct node
{
int s, t;
int lca;
} path[N];
int head[N], nex[2 * N], val[2 * N], to[2 * N], idx;
int u, v, w;
void add(int u, int v, int w)
{to[idx] = v;
val[idx] = w;
nex[idx] = head[u];
head[u] = idx++;
}
int que[N];
void bfs(int root)
{memset(depth, 0x3f, sizeof(depth));
depth[0]=0;
depth[root] = 1;
int h = 0, t = 0;
que[t++] = root;
while (h != t)
{int top = que[h++];
for (int i = head[top]; ~i; i = nex[i])
{int j = to[i];
int w = val[i];
if (depth[j] > depth[top] + 1)
{depth[j] = depth[top] + 1;
dist[j] = dist[top] + val[i];
que[t++] = j;
pre[j] = val[i];
fa[j][0] = top;
for (int k = 1; k <=21; k ++)
{fa[j][k] = fa[fa[j][k - 1]][k - 1];
}
}
}
}
}
int get_lca(int u, int v)
{if (depth[u] < depth[v])
{swap(u, v);
}
// 第一步:先让 u 跳到与 v 同一高度
for (int i = 21; i >= 0; i--)
{if (depth[fa[u][i]] >= depth[v])
{u = fa[u][i];
}
}
if (u == v) // 非凡状况,u 和 v 调到同一高度之后重合,只需返回 u 或 v 即可
{return u;}
// 第二步,让 u 和 v 跳到最近公共先人的下一层
for (int i = 21; i >= 0; i--)
{if (fa[u][i] != fa[v][i])
{u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][0]; // 再向上跳一步就是 root
}
int judge(int a,int f,int cnt,int maxn)
{for(int i=head[a];~i;i=nex[i])
{int j=to[i];
if(j==f)
{continue;}
tmp[a]+=judge(j,a,cnt,maxn);
}
if(tmp[a]==cnt&&pre[a]>=maxn)
{flag=1;}
return tmp[a];
}
bool check(int x)
{memset(tmp, 0, sizeof(tmp));
cnt = 0,flag=0;
int maxn = 0;
for (int i = 1; i <= m; i++)
{int dis = dist[path[i].s] + dist[path[i].t] - 2 * dist[path[i].lca];
if (dis > x)
{
cnt++;
maxn = max(maxn, dis - x);
//s,t 加一,最近公共先人 -2
tmp[path[i].s]++;
tmp[path[i].t]++;
tmp[path[i].lca] -= 2;
}
}
if (!cnt)
{return true;}
judge(1,0,cnt,maxn);
if(flag)
{return true;}
return false;
}
int main()
{scanf("%d %d", &n, &m);
memset(head, -1, sizeof(head));
for (int i = 0; i < n - 1; i++)
{scanf("%d %d %d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
bfs(1);
for (int i = 1; i <= m; i++)
{scanf("%d %d", &path[i].s, &path[i].t);
path[i].lca = get_lca(path[i].s, path[i].t);
}
// 二分找正确答案
long long int l = 0, r = 3000000000;
while (l < r)
{int mid = (l + r) / 2;
if (check(mid))
{r = mid;}
else
{l = mid + 1;}
}
cout << l << endl;
return 0;
}
正文完