洛谷P3038 [USACO11DEC]牧草种植Grass Planting
树链剖分或者树上差分
树链剖分只能对点进行操作,所以把边权化为点权。树上化边权为点权的一般操作是把边权赋到深度较深的点里。
然后用树链剖分+线段树更改权值路径和+单点查询即可解决该问题。
#include <bits/stdc++.h>
#define N 4001011
#define ls l, mid, root << 1
#define rs mid + 1, r, root << 1 | 1
using namespace std;
struct edg {
int to, nex;
}e[N * 4];
int lin[N], dep[N], fat[N], siz[N], son[N], data[N], dfn[N], top[N], temp[N], cnt, n, m, tot;//data[i]表示i的点权。
int tree[N << 2], lazy[N << 2];
inline void add(int f, int t)//默认边权为0
{
e[++cnt].nex = lin[f];
e[cnt].to = t;
lin[f] = cnt;
}
void dfs1(int now, int fa)
{
dep[now] = dep[fa] + 1;
fat[now] = fa;
siz[now] = 1;
for (int i = lin[now]; i; i = e[i].nex)
{
int to = e[i].to;
if (to == fa) continue;
dfs1(to, now);
siz[now] += siz[to];
if (siz[to] > siz[son[now]])
son[now] = to;
}
}
void dfs2(int now, int tes) //求出dfs序, 树链剖分求lca
{
dfn[now] = ++tot;//dfn是dfs序
top[now] = tes;
if (!son[now]) return;
dfs2(son[now], tes);
for (int i = lin[now]; i; i = e[i].nex)//找重链
{
int to = e[i].to;
if (to == fat[now] || to == son[now]) continue;
dfs2(to, to);
}
}
inline void pushup(int root) {tree[root] = tree[root << 1] + tree[root << 1 | 1];}
void build(int l, int r, int root)
{
if (l == r)
{
tree[root] = 0;
return;
}
int mid = (l + r) >> 1;
build(ls), build(rs);
pushup(root);
}
void pushdown(int l, int r, int root)
{
int mid = (l + r) >> 1;
if (lazy[root])
{
lazy[root << 1] += lazy[root];
lazy[root << 1 | 1] += lazy[root];
tree[root << 1] += lazy[root] * (mid - l + 1);
tree[root << 1 | 1] += lazy[root] * (r - mid);
lazy[root] = 0;
}
}
int query(int pos, int l, int r, int root)
{
if (l == r)
return tree[root];
int res = 0, mid = (l + r) >> 1;
pushdown(l, r, root);
if (pos <= mid)
res += query(pos, ls);
else
res += query(pos, rs);
return res;
}
void update(int ql, int qr, int add, int l, int r, int root)
{
if (ql <= l && r <= qr)
{
tree[root] += (r - l + 1) * add;
lazy[root] += add;
return;
}
pushdown(l, r, root);
int mid = (l + r) >> 1;
if (ql <= mid)
update(ql, qr, add, ls);
if (qr > mid)
update(ql, qr, add, rs);
pushup(root);
}
void U(int x, int y)
{
while (top[x] != top[y])//找他们的lca
{
if (dep[top[x]] < dep[top[y]]) swap(x, y);
update(dfn[top[x]], dfn[x], 1, 1, n, 1);
x = fat[top[x]];
}
if (dep[x] > dep[y])
swap(x, y);
update(dfn[x] + 1, dfn[y], 1, 1, n, 1);
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1, a, b; i < n; i++) {scanf("%d%d", &a, &b), add(a, b), add(b, a);}
dfs1(1, 0);
dfs2(1, 1);
build(1, n, 1);
while (m--)
{
char flag; int a, b;
cin >> flag >> a >> b;
if (flag == 'P')
U(a, b);
else
{
if (dep[a] < dep[b]) swap(a, b);
printf("%d\n", query(dfn[a], 1, n, 1));
}
}
return 0;
}