【链接】
https://www.luogu.org/problemnew/show/P3038
【题意】
给出一棵n个节点的树,有m个操作,操作为将一条路径上的边权加一或询问某条边的权值。
【思路】
树链剖分的裸题。
但是这个题是在边上进行操作,我们考虑把边上的操作转移到点上首先想一下最简单的链的情况。
对于区间[l,r][l,r]的操作会影响r−l+1r−l+1个点,但只会影响r−lr−l条边,那么我们可以把每条边的边权都放在与它相连的两个点
深度较深的点上,所以我们每次修改的时候都对(l,r](l,r]进行修改,查询的时候也如此,具体怎么实现呢?
只需要在查询/修改的时候把左区间+1即可。注意特判一下x==y的情况
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 6;
const int mod = 1e9 + 7;
vector<int>v[maxn];
int a[maxn];
int deep[maxn];
int fa[maxn];
int tot[maxn];
int top[maxn];
int son[maxn];
int idx[maxn];
int b[maxn];
int cnt = 0;
int root = 1;
struct node {
int l, r, size, v, lazy;
}t[maxn];
int dfs1(int now, int f, int dep) {
deep[now] = dep;
fa[now] = f;
tot[now] = 1;
int maxson = -1;
for (int x : v[now]) {
if (x == f)continue;
tot[now] += dfs1(x, now, dep + 1);
if (tot[x] > maxson) {
maxson = tot[x];
son[now] = x;
}
}
return tot[now];
}
void dfs2(int now, int topf) {
idx[now] = ++cnt;
a[cnt] = b[now];
top[now] = topf;
if (!son[now])return;
dfs2(son[now], topf);
for (int nxt : v[now]) {
if (!idx[nxt]) {
dfs2(nxt, nxt);
}
}
}
void update(int p) {
t[p].v = (t[p << 1].v + t[p << 1 | 1].v + mod) % mod;
}
void pushdown(int p) {
if (t[p].lazy) {
t[p << 1].v = (t[p << 1].v + t[p].lazy*t[p << 1].size) % mod;
t[p << 1 | 1].v = (t[p << 1 | 1].v + t[p].lazy*t[p << 1 | 1].size) % mod;
t[p << 1].lazy = (t[p << 1].lazy + t[p].lazy) % mod;
t[p << 1 | 1].lazy = (t[p << 1 | 1].lazy + t[p].lazy) % mod;
t[p].lazy = 0;
}
}
void build(int p, int l, int r) {
t[p].l = l;
t[p].r = r;
t[p].size = r - l + 1;
if (l == r) {
t[p].v = a[l];
return;
}
int mid = (l + r) >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
update(p);
}
void intervalAdd(int p, int l, int r, int val) {
if (l <= t[p].l&&r >= t[p].r) {
t[p].v += t[p].size*val;
t[p].lazy += val;
return;
}
pushdown(p);
int mid = (t[p].l + t[p].r) >> 1;
if (l <= mid)intervalAdd(p << 1, l, r, val);
if (r > mid)intervalAdd(p << 1 | 1, l, r, val);
update(p);
}
int intervalAsk(int p, int l, int r) {
if (l <= t[p].l&&r >= t[p].r) {
return t[p].v;
}
pushdown(p);
int mid = (t[p].l + t[p].r) >> 1;
int ans = 0;
if (l <= mid)ans += intervalAsk(p << 1, l, r);
if (r > mid)ans += intervalAsk(p << 1 | 1, l, r);
return ans;
}
int treeSum(int x, int y) {
int ans = 0;
while (top[x] != top[y]) {
if (deep[top[x]] < deep[top[y]]) swap(x, y);
ans += intervalAsk(1, idx[top[x]], idx[x]);
x = fa[top[x]];
}
if (deep[x] > deep[y])swap(x, y);
if(x!=y)ans += intervalAsk(1, idx[x]+1, idx[y]);
return ans;
}
void treeAdd(int x, int y, int val) {
while (top[x] != top[y]) {
if (deep[top[x]] < deep[top[y]])swap(x, y);
intervalAdd(1, idx[top[x]], idx[x], val);
x = fa[top[x]];
}
if (deep[x] > deep[y])swap(x, y);
if (x==y)return;
intervalAdd(1, idx[x]+1, idx[y], val);
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i < n; i++) {
int x, y;
scanf("%d%d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
}
dfs1(root, 0, 1);
dfs2(root, root);
build(1, 1, n);
while (m--) {
char op[3];
int x, y;
scanf("%s%d%d", op, &x, &y);
if (op[0] == 'P') {
treeAdd(x, y, 1);
}
else {
printf("%d\n", treeSum(x,y));
}
}
}