区间问题----多次区间修改,少次单点询问的差分
《定义》
对于原数列:a1 a2 a3.....ai aj........an-1 an
这个数列的差分为ca[j]=aj-ai
这个数列的前缀和为he[j]=aj+ai+..+a2+a1
我们可以惊奇的发现
差分的前缀和==原数列
前缀和的差分==原数列
利用这个性质:
差分还有一个惊人的特性:
差分可以将将在原数组上的区间修改问题,转化为在差分数组上的两次单点修改问题
差分还可以将在原数组上的单点查询问题,转化为在差分数组上的前缀和问题
《树上差分》
比如这道题:
1 #include <iostream>
2 #include <algorithm>
3 #include <cstring>
4 #include <vector>
5 using namespace std;
6 const int N = 100005;
7 vector<int> tree[N];
8 // ca[i]表示点i管理的边权的差分;
9 // ans[i]表示点i管理的边权;
10 //树上差分,叶子节点开始,根节点为停止
11 int ca[N], ans[N];
12 int sizer[N], f[N], dep[N], son[N];
13 void dfs1(int x, int from, int d)
14 {
15 f[x] = from, dep[x] = d, sizer[x] = 1, son[x] = -1;
16 for (int i = 0; i < tree[x].size(); i++)
17 {
18 int child = tree[x][i];
19 if (child == from)
20 continue;
21 dfs1(child, x, d + 1);
22 sizer[x] += sizer[child];
23 if (son[x] == -1 || sizer[son[x]] < sizer[child])
24 son[x] = child;
25 }
26 }
27 int top[N], id[N], rk[N], cnt = 0;
28 void dfs2(int x, int from, int t)
29 {
30 ++cnt;
31 id[x] = cnt, rk[cnt] = x, top[x] = t;
32 if (son[x] != -1)
33 dfs2(son[x], x, t);
34 for (int i = 0; i < tree[x].size(); i++)
35 {
36 int child = tree[x][i];
37 if (child == from || child == son[x])
38 continue;
39 dfs2(child, x, child);
40 }
41 }
42 int lca(int a, int b)
43 {
44 while (top[a] != top[b])
45 {
46 if (dep[top[a]] < dep[top[b]])
47 swap(a, b);
48 a = f[top[a]];
49 }
50 if (dep[a] > dep[b])
51 swap(a, b);
52 return a;
53 }
54 void preSum(int x, int from)
55 {
56 ans[x] = ca[x];
57 for (int i = 0; i < tree[x].size(); i++)
58 {
59 int child = tree[x][i];
60 if (child == from)
61 continue;
62 //总之,先到叶子节点
63 preSum(child, x);
64 ans[x] += ans[child];
65 /* cout << "! "
66 << "child " << child << " "
67 << "ans[child] " << ans[child] << " "
68 << "node:" << x << " "
69 << "ans[x] " << ans[x] << endl; */
70 }
71 }
72 int main()
73 {
74 int n;
75 scanf("%d", &n);
76 pair<int, int> side[N];
77 for (int i = 1; i <= n - 1; i++)
78 {
79 int a, b;
80 scanf("%d%d", &a, &b);
81 side[i] = {a, b};
82 tree[a].push_back(b), tree[b].push_back(a);
83 }
84 //用树剖求解lca
85 dfs1(1, -1, 1);
86 dfs2(1, -1, 1);
87 int m;
88 scanf("%d", &m);
89 while (m--)
90 {
91 int x, y;
92 scanf("%d%d", &x, &y);
93 if (dep[x] < dep[y])
94 swap(x, y);
95 //因为这里改变的权重为1,直接++即可
96 if (top[x] != top[y])
97 ca[x]++, ca[y]++, ca[lca(x, y)] -= 2;
98 else
99 ca[x]++, ca[y]--;
100 }
101 preSum(1, -1);
102 for (int i = 1; i <= n - 1; i++)
103 {
104 int x = side[i].first, y = side[i].second;
105 if (dep[x] < dep[y])
106 swap(x, y);
107 printf("%d ", ans[x]);
108 }
109 return 0;
110 }
这里讲一下关于根节点的ans[root]其是一直为的