一、点差分
对于树上路径
p
a
t
h
(
u
,
v
)
path(u,v)
path(u,v)
d
l
t
[
u
]
+
+
,
d
l
t
[
v
]
+
+
,
d
l
t
[
l
c
a
(
u
,
v
)
]
−
−
,
d
l
t
[
f
(
l
c
a
(
u
,
v
)
)
]
−
−
dlt[u]++, dlt[v]++, dlt[lca(u, v)] --, dlt[f(lca(u, v))] --
dlt[u]++,dlt[v]++,dlt[lca(u,v)]−−,dlt[f(lca(u,v))]−−
询问点
x
x
x 被多少个标记覆盖时
d
f
s
dfs
dfs
从根节点开始,将其本身的权值加上所有子节点的权值
每个节点的权值既是其被路径覆盖的次数
洛谷 P3128 最大流
模板:
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const ll mod = 1e9 + 7;
const int maxn = 3e5 + 10;
const int maxm = 2e5 + 10;
int n, k, f[maxn][25];
int cnt, head[maxn];
int dep[maxn], dlt[maxn];
struct EDGE {
int next, to, w;
} edge[maxn<<2];
void add(int u, int v, int w) {
edge[++cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt;
}
void dfs1(int cur, int fa, int de){
dep[cur] = de;
f[cur][0] = fa;
for(int i=1; i<=20; i++)
f[cur][i] = f[f[cur][i-1]][i-1];
for(int i=head[cur]; i; i=edge[i].next){
if(edge[i].to == fa) continue;
dfs1(edge[i].to, cur, de+1);
}
}
int lca(int x, int y){
if(dep[x]<dep[y]) swap(x, y);
for(int i=20; i>=0; i--)
if(dep[f[x][i]]>=dep[y])
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];
}
void dfs2(int u){
for(int i=head[u]; i; i=edge[i].next){
if(edge[i].to==f[u][0]) continue;
dfs2(edge[i].to);
dlt[u] += dlt[edge[i].to];
}
}
int main() {
scanf("%d%d", &n, &k);
for(int i=1; i<n; i++){
int u, v;
scanf("%d%d", &u, &v);
add(u, v, 1);
add(v, u, 1);
}
dfs1(1, 0, 1);
for(int i=0, u, v; i<k; i++){
scanf("%d%d", &u, &v);
int fa = lca(u, v);
dlt[u]++, dlt[v]++;
dlt[fa]--;
dlt[f[fa][0]]--;
}
dfs2(1);
int ans = 0;
for(int i=1; i<=n; i++) ans = max(ans, dlt[i]);
printf("%d\n", ans);
}
二、边差分
对于树上路径
p
a
t
h
(
u
,
v
)
path(u,v)
path(u,v)
d
l
t
[
u
]
+
+
,
d
l
t
[
v
]
+
+
,
d
l
t
[
l
c
a
(
u
,
v
)
]
−
=
2
dlt[u]++, dlt[v]++, dlt[lca(u, v)] -=2
dlt[u]++,dlt[v]++,dlt[lca(u,v)]−=2
询问点
x
x
x 与其父亲的连边被多少个标记覆盖时
d
f
s
dfs
dfs
从根节点开始,将其本身的权值加上所有子节点的权值
每个节点的权值即表示与其父亲的连边,被路径覆盖的次数
例题一:洛谷 P2680 运输计划
模板:
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const ll mod = 1e9 + 7;
const int maxn = 3e5 + 10;
int n, m, f[maxn][25];
int cnt, head[maxn], dep[maxn];
int a[maxn], b[maxn], l[maxn];
int dis[maxn], dist[maxn];
int rk[maxn], rks, topre[maxn];
int maxjob, dlt[maxn];
struct EDGE {
int next, to, w;
} edge[maxn<<2];
void add(int u, int v, int w) {
edge[++cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt;
}
void dfs(int cur, int fa, int de){
rk[++rks] = cur;
dep[cur] = de;
f[cur][0] = fa;
for(int i=1; i<=20; i++)
f[cur][i] = f[f[cur][i-1]][i-1];
for(int i=head[cur]; i; i=edge[i].next){
if(edge[i].to == fa) continue;
topre[edge[i].to] = edge[i].w;
dis[edge[i].to] = dis[cur] + edge[i].w;
dfs(edge[i].to, cur, de+1);
}
}
int lca(int x, int y){
if(dep[x]<dep[y]) swap(x, y);
for(int i=20; i>=0; i--)
if(dep[f[x][i]]>=dep[y])
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];
}
bool check(int k){
memset(dlt, 0, sizeof(dlt));
int tot = 0;
for(int i=1; i<=m; i++)
if(dist[i] > k){
dlt[a[i]]++, dlt[b[i]]++;
dlt[l[i]] -= 2, tot++;
}
for(int i=n; i; i--){
dlt[f[rk[i]][0]] += dlt[rk[i]];
if(topre[rk[i]]>=maxjob-k && dlt[rk[i]]==tot)
return true;
}
return false;
}
int main() {
scanf("%d%d", &n, &m);
for(int i=1; i<n; i++){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
dfs(1, 0, 1);
for(int i=1; i<=m; i++){
scanf("%d%d", a+i, b+i);
l[i] = lca(a[i], b[i]);
dist[i] = dis[a[i]] + dis[b[i]] - 2*dis[l[i]];
maxjob = max(maxjob, dist[i]);
}
int l = 0, r = maxjob, mid;
while(l<=r){
mid = l + r >> 1;
if(check(mid)) r = mid - 1;
else l = mid + 1;
}
printf("%d\n", l);
}
例题二:POJ 3417
模板:
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const ll mod = 1e9 + 7;
const int maxn = 3e5 + 10;
int n, m, f[maxn][25];
int cnt, head[maxn], dep[maxn];
int rk[maxn], rks, dlt[maxn];
struct EDGE {
int next, to, w;
} edge[maxn<<2];
void add(int u, int v, int w) {
edge[++cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt;
}
void dfs(int cur, int fa, int de){
rk[++rks] = cur;
dep[cur] = de;
f[cur][0] = fa;
for(int i=1; i<=20; i++)
f[cur][i] = f[f[cur][i-1]][i-1];
for(int i=head[cur]; i; i=edge[i].next){
if(edge[i].to == fa) continue;
dfs(edge[i].to, cur, de+1);
}
}
int lca(int x, int y){
if(dep[x]<dep[y]) swap(x, y);
for(int i=20; i>=0; i--)
if(dep[f[x][i]]>=dep[y])
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 main() {
scanf("%d%d", &n, &m);
for(int i=1; i<n; i++){
int u, v;
scanf("%d%d", &u, &v);
add(u, v, 1);
add(v, u, 1);
}
dfs(1, 0, 1);
for(int i=0; i<m; i++){
int u, v;
scanf("%d%d", &u, &v);
dlt[u]++, dlt[v]++;
dlt[lca(u, v)] -= 2;
}
for(int i=n; i; i--)
dlt[f[rk[i]][0]] += dlt[rk[i]];
int ans = 0;
for(int i=2; i<=n; i++){
if(dlt[rk[i]] == 0) ans += m;
else if(dlt[rk[i]] == 1) ans++;
}
printf("%d\n", ans);
}