• DFS序常见用法及代码实现


    dfs序就是一棵树在dfs遍历时组成的节点序列.

    它有这样一个特点:一棵子树的dfs序是一个区间. 下面是dfs序的基本代码:

     1 void dfs(int x,int pre,int d){//L,R表示一个子树的范围
     2     L[x]=++tot;
     3     dep[x]=d;
     4     for(int i=0;i<e[x].size();i++){
     5         int y=e[x][i];
     6         if(y==pre)continue;
     7         dfs(y,x,d+1);
     8     }
     9     R[x]=tot;
    10 }

    给定一颗树, 和每个节点的权值.下面有7个经典的关于dfs序的问题:

    下面所有问题都采用如图的树作为样例

    都有以下初始化建树代码:

     1 const int n = 15;
     2 const int maxn = 1010;
     3 struct E{
     4     int to,next;
     5 }edge[maxn];
     6 int head[maxn], cnt;
     7 int t[maxn];
     8 inline void addedge(int u,int v){
     9     edge[cnt] = (E){v,head[u]};
    10     head[u] = cnt++;
    11     edge[cnt] = (E){u,head[v]};
    12     head[v] = cnt++;
    13 }
    14 void build(){
    15     memset(head, -1, sizeof head);
    16     int tmp[28] = {1,2,1,3,2,4,2,5,2,6,3,7,3,8,5,9,5,10,7,11,7,12,12,13,12,14,12,15};
    17     for (int i = 0; i < 14*2; i+=2){
    18         addedge(tmp[i],tmp[i+1]);
    19     }
    20 }

    1.对某个节点X权值加上一个数W, 查询某个子树X里所有点权的和.

    由于X的子树在DFS序中是连续的一段, 只需要维护一个dfs序列,用树状数组实现:单点修改和区间查询.

    代码实现:

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 
     6 const int n = 15;
     7 const int maxn = 1010;
     8 struct E{
     9     int to,next;
    10 }edge[maxn];
    11 int head[maxn], cnt;
    12 int t[maxn];
    13 inline void addedge(int u,int v){
    14     edge[cnt] = (E){v,head[u]};
    15     head[u] = cnt++;
    16     edge[cnt] = (E){u,head[v]};
    17     head[v] = cnt++;
    18 }
    19 void build(){
    20     memset(head, -1, sizeof head);
    21     int tmp[28] = {1,2,1,3,2,4,2,5,2,6,3,7,3,8,5,9,5,10,7,11,7,12,12,13,12,14,12,15};
    22     for (int i = 0; i < 14*2; i+=2){
    23         addedge(tmp[i],tmp[i+1]);
    24     }
    25 }
    26 
    27 
    28 int L[maxn], R[maxn], tot; //l[pos]表示子树的根(编号为pos的子树的dfs序号) R[pos]表示子树结尾的点 L[pos] ~ R[pos]表示以pos为根的子树 
    29 void dfs(int u,int pre){
    30     L[u] = ++tot;
    31     for (int i = head[u]; ~i; i = edge[i].next){
    32         int v = edge[i].to;
    33         if (v == pre) continue;
    34         dfs(v,u);
    35     }
    36     R[u] = tot;
    37 }
    38 
    39 
    40 int tree[maxn];
    41 int lowbit(int x){return x & -x;}
    42 int add(int x,int w){
    43     while (x <= n){
    44         tree[x] += w;
    45         x += lowbit(x);
    46     }
    47 }//对每个节点x加上w 
    48 int sum(int x){
    49     int res = 0;
    50     while (x > 0){
    51         res += tree[x];
    52         x -= lowbit(x);
    53     }
    54     return res;
    55 }
    56 int query(int x){
    57     return sum(R[x]) - sum(L[x]-1);
    58 }// 查询编号为x的子树里所有点的权值和 
    59 
    60 
    61 int main(){
    62     build();
    63     dfs(1,-1);
    64     string op; // 输入Q x表示查询编号为x的子树里所有点权值和 Add x w表示在x节点加上w的权值 
    65     int x, w;
    66     while (cin >> op){
    67         if (op == "Q"){
    68             cin >> x;
    69             cout << query(x) << endl;
    70         } else {
    71             cin >> x >> w;
    72             add(L[x], w);
    73         }
    74     }
    75     return 0;
    76 }
    77 /*
    78 input : 
    79 Add 5 1
    80 Add 6 1
    81 Q 2
    82 Add 7 2
    83 Add 12 3
    84 Add 13 1
    85 Q 12
    86 Q 3
    87 Q 1
    88 output : 
    89 2
    90 4
    91 6
    92 8
    93 */

     2. 对节点X到Y的最短路上所有点权都加一个数W, 查询某个点的权值.
    这个操作等价于

    a. 对X到根节点路径上所有点权加W
    b. 对Y到根节点路径上所有点权加W
    c. 对LCA(x, y)到根节点路径上所有点权值减W
    d. 对LCA(x,y)的父节点 fa(LCA(x, y))到根节点路径上所有权值减W

    于是要进行四次这样从一个点到根节点的区间修改.将问题进一步简化, 进行一个点X到根节点的区间修改, 查询其他一点Y时,只有X在Y的子树内, X对Y的值才有贡献且贡献值为W.当单点更新X时,X实现了对X到根的路径上所有点贡献了W.于是只需要更新四个点(单点更新) ,查询一个点的子树内所有点权的和(区间求和)即可.

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 const int n = 15;
      4 const int maxn = 1010;
      5 
      6 const int lca_maxn = 1010;
      7 const int tree_deep = 25;
      8 int fa[lca_maxn][tree_deep];
      9 int dep[lca_maxn], lg[lca_maxn];
     10 
     11 void init_lg(){
     12     for(int i = 1; i <= n; ++i) //log_2(i)+1
     13     lg[i] = lg[i-1] + (1 << lg[i-1] == i);
     14 }
     15 
     16 struct E{
     17     int to,next;
     18 }edge[maxn];
     19 int head[maxn], cnt;
     20 int t[maxn];
     21 inline void addedge(int u,int v){
     22     edge[cnt] = (E){v,head[u]};
     23     head[u] = cnt++;
     24     edge[cnt] = (E){u,head[v]};
     25     head[v] = cnt++;
     26 }
     27 void build(){
     28     memset(head, -1, sizeof head);
     29     int tmp[28] = {1,2,1,3,2,4,2,5,2,6,3,7,3,8,5,9,5,10,7,11,7,12,12,13,12,14,12,15};
     30     for (int i = 0; i < 14*2; i+=2){
     31         addedge(tmp[i],tmp[i+1]);
     32     }
     33 }
     34 
     35 
     36 void dfs_lca(int u,int pre){
     37     fa[u][0] = pre, dep[u] = dep[pre] + 1;
     38     for (register int i = 1; i <= lg[dep[u]]; ++i){
     39         fa[u][i] = fa[fa[u][i-1]][i-1];
     40     }
     41     for (register int i = head[u]; ~i; i = edge[i].next){
     42         int v = edge[i].to; if (v != pre) dfs_lca(v,u);
     43     }
     44 }
     45 int lca(int x, int y){
     46     if (dep[x] < dep[y]) swap(x, y);
     47     while (dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];
     48     if (x == y) return x;
     49     for (register int i = lg[dep[x] - 1]; i >= 0; --i){
     50         if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
     51     }
     52     return fa[x][0];
     53 }
     54 
     55 int L[maxn], R[maxn], tot, father[maxn];
     56 int dfs(int u, int pre){
     57     father[u] = pre;
     58     L[u] = ++tot;
     59     for (int i = head[u]; ~i; i = edge[i].next) {
     60         int v = edge[i].to;
     61         if (v == pre) continue;
     62         dfs(v, u);
     63     }
     64     R[u] = tot;
     65 }
     66 
     67 int tree[maxn];
     68 int lowbit(int x) { return x & -x;}
     69 void update(int x, int val){
     70     while (x <= n) {
     71         tree[x] += val;
     72         x += lowbit(x);
     73     }
     74 }
     75 int sum (int x){
     76     int res = 0;
     77     while (x > 0) {
     78         res += tree[x];
     79         x -= lowbit(x);
     80     }
     81     return res;
     82 }
     83 int query (int x){
     84     return sum(R[x]) - sum(L[x]-1);
     85 }
     86 
     87 int add(int x,int y, int v){
     88     int LCA = lca(x, y);
     89     update(L[x], v);
     90     update(L[y], v);
     91     update(L[LCA], -v);
     92     if (father[LCA])
     93     update(L[father[LCA]], -v);
     94 }
     95 
     96 int main(){
     97     init_lg();
     98     build();
     99     dfs(1, 0);
    100     dfs_lca(1,0);
    101     string op;
    102     int x, y, w;
    103     while (cin >> op) {
    104         if (op == "Q") {// 输入Q x表示查询编号为x的点的权值 Add x y w表示在x节点到y节点的最短路上加上w的权值
    105             cin >> x;
    106             cout << query(x) << endl;
    107         } else {
    108             cin >> x >> y >> w;
    109             add(x, y, w);
    110         } 
    111     }
    112     return 0;
    113 }
    114 /*
    115 input : 
    116 Add 10 12 1
    117 Add 3 9 2
    118 Q 1
    119 Q 11
    120 Q 5
    121 Q 9
    122 Add 1 1 -1
    123 Q 1
    124 output : 
    125 3
    126 0
    127 3
    128 2
    129 2
    130 */

     3.对节点X到Y的最短路上所有点权都加一个数W, 查询某个点子树的权值之和
    同问题2中的修改方法, 转化为修改某点到根节点的权值加/减W
    当修改某个节点A, 查询另一节点B时
    只有A在B的子树内, Y的值会增加W×(depth[A]depth[B]+1)==W×(depth[A]+1)W×depth[B]W×(depth[A]−depth[B]+1)==W×(depth[A]+1)−W×depth[B]
    同样是用树状数组来查询Y的子树, 修改 和 查询方法都要新增一个数组
    第一个数组保存 W×(depth[A]+1)W×(depth[A]+1), 第二个数组保存 W
    每次查询结果为Sum(ed[B])Sum(st[B]1)(Sum1(ed[B])Sum(st[B]1))×depth[B]

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 const int n = 15;
      4 const int maxn = 1010;
      5 
      6 const int lca_maxn = 1010;
      7 const int tree_deep = 25;
      8 int fa[lca_maxn][tree_deep];
      9 int dep[lca_maxn], lg[lca_maxn];
     10 
     11 void init_lg(){
     12     for(int i = 1; i <= n; ++i) //log_2(i)+1
     13     lg[i] = lg[i-1] + (1 << lg[i-1] == i);
     14 }
     15 
     16 struct E{
     17     int to,next;
     18 }edge[maxn];
     19 int head[maxn], cnt;
     20 int t[maxn];
     21 inline void addedge(int u,int v){
     22     edge[cnt] = (E){v,head[u]};
     23     head[u] = cnt++;
     24     edge[cnt] = (E){u,head[v]};
     25     head[v] = cnt++;
     26 }
     27 void build(){
     28     memset(head, -1, sizeof head);
     29     int tmp[28] = {1,2,1,3,2,4,2,5,2,6,3,7,3,8,5,9,5,10,7,11,7,12,12,13,12,14,12,15};
     30     for (int i = 0; i < 14*2; i+=2){
     31         addedge(tmp[i],tmp[i+1]);
     32     }
     33 }
     34 
     35 
     36 void dfs_lca(int u,int pre){
     37     fa[u][0] = pre, dep[u] = dep[pre] + 1;
     38     for (register int i = 1; i <= lg[dep[u]]; ++i){
     39         fa[u][i] = fa[fa[u][i-1]][i-1];
     40     }
     41     for (register int i = head[u]; ~i; i = edge[i].next){
     42         int v = edge[i].to; if (v != pre) dfs_lca(v,u);
     43     }
     44 }
     45 int lca(int x, int y){
     46     if (dep[x] < dep[y]) swap(x, y);
     47     while (dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];
     48     if (x == y) return x;
     49     for (register int i = lg[dep[x] - 1]; i >= 0; --i){
     50         if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
     51     }
     52     return fa[x][0];
     53 }
     54 
     55 int L[maxn], R[maxn], tot, father[maxn];
     56 int dfs(int u, int pre){
     57     father[u] = pre;
     58     L[u] = ++tot;
     59     for (int i = head[u]; ~i; i = edge[i].next) {
     60         int v = edge[i].to;
     61         if (v == pre) continue;
     62         dfs(v, u);
     63     }
     64     R[u] = tot;
     65 }
     66 
     67 int tree1[maxn];
     68 int lowbit(int x) { return x & -x;}
     69 void update1(int x, int val){
     70     while (x <= n) {
     71         tree1[x] += val;
     72         x += lowbit(x);
     73     }
     74 }
     75 int sum1 (int x){
     76     int res = 0;
     77     while (x > 0) {
     78         res += tree1[x];
     79         x -= lowbit(x);
     80     }
     81     return res;
     82 }
     83 
     84 int tree2[maxn];
     85 void update2(int x,int val) {
     86     while (x <= n) {
     87         tree2[x] += val;
     88         x += lowbit(x);
     89     }
     90 }
     91 int sum2 (int x){
     92     int res = 0;
     93     while (x > 0){
     94         res += tree2[x];
     95         x -= lowbit(x);
     96     }
     97     return res;
     98 }
     99 int add(int x,int y, int v){
    100     int LCA = lca(x, y);
    101     update1(L[x], v);
    102     update2(L[x], (v*(dep[x]+1)));
    103     update1(L[y], v);
    104     update2(L[y], (v*(dep[y]+1)));
    105     update1(L[LCA], -v);
    106     update2(L[LCA], (-v*(dep[LCA]+1)));
    107     if (father[LCA])
    108     update1(L[father[LCA]], -v),update2(L[father[LCA]],(-v*(dep[father[LCA]]+1)));
    109 }
    110 
    111 int query(int x){
    112     return sum2(R[x]) - sum2(L[x]-1) - dep[x] * (sum1(R[x]) - sum1(L[x]-1));
    113 }
    114 
    115 int main(){
    116     init_lg();
    117     build();
    118     dfs(1, 0);
    119     dfs_lca(1,0);
    120     string op;
    121     int x, y, w;
    122     while (cin >> op) {
    123         if (op == "Q") {// 输入Q x表示查询编号为x的子树里所有点权值和 Add x y w表示在x节点到y节点的最短路上加上w的权值
    124             cin >> x;
    125             cout << query(x) << endl;
    126         } else {
    127             cin >> x >> y >> w;
    128             add(x, y, w);
    129         } 
    130     }
    131     return 0;
    132 }
    133 /*
    134 input : 
    135 Add 9 11 1
    136 Q 2
    137 Q 1
    138 Q 7
    139 Add 3 15 2
    140 Q 3
    141 output : 
    142 3
    143 7
    144 2
    145 11
    146 */

    4.单点更新,树链和查询

    树链和查询与树链修改类似,树链和(x,y)等于下面四个部分和相加:

    1).x到根节点的链上所有节点权值加。

    2).y到根节点的链上所有节点权值加。

    3).lca(x,y)到根节点的链上所有节点权值和的-1倍。

    4).fa(lca(x,y))到根节点的链上所有节点权值和的-1倍。

    所以问题转化为:查询点x到根节点的链上的所有节点权值和。

    修改节点x权值,当且仅当y是x的子孙节点时,x对y的值有贡献。

    差分前缀和,y的权值等于dfs中[1,l[y]]的区间和。

    单点修改:add(l[x],v),add(r[x]+1,-v);

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 const int n = 15;
      4 const int maxn = 1010;
      5 
      6 const int lca_maxn = 1010;
      7 const int tree_deep = 25;
      8 int fa[lca_maxn][tree_deep];
      9 int dep[lca_maxn], lg[lca_maxn];
     10 
     11 void init_lg(){
     12     for(int i = 1; i <= n; ++i) //log_2(i)+1
     13     lg[i] = lg[i-1] + (1 << lg[i-1] == i);
     14 }
     15 
     16 struct E{
     17     int to,next;
     18 }edge[maxn];
     19 int head[maxn], cnt;
     20 int t[maxn];
     21 inline void addedge(int u,int v){
     22     edge[cnt] = (E){v,head[u]};
     23     head[u] = cnt++;
     24     edge[cnt] = (E){u,head[v]};
     25     head[v] = cnt++;
     26 }
     27 void build(){
     28     memset(head, -1, sizeof head);
     29     int tmp[28] = {1,2,1,3,2,4,2,5,2,6,3,7,3,8,5,9,5,10,7,11,7,12,12,13,12,14,12,15};
     30     for (int i = 0; i < 14*2; i+=2){
     31         addedge(tmp[i],tmp[i+1]);
     32     }
     33 }
     34 
     35 
     36 void dfs_lca(int u,int pre){
     37     fa[u][0] = pre, dep[u] = dep[pre] + 1;
     38     for (register int i = 1; i <= lg[dep[u]]; ++i){
     39         fa[u][i] = fa[fa[u][i-1]][i-1];
     40     }
     41     for (register int i = head[u]; ~i; i = edge[i].next){
     42         int v = edge[i].to; if (v != pre) dfs_lca(v,u);
     43     }
     44 }
     45 int lca(int x, int y){
     46     if (dep[x] < dep[y]) swap(x, y);
     47     while (dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];
     48     if (x == y) return x;
     49     for (register int i = lg[dep[x] - 1]; i >= 0; --i){
     50         if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
     51     }
     52     return fa[x][0];
     53 }
     54 
     55 int L[maxn], R[maxn], tot, father[maxn];
     56 int dfs(int u, int pre){
     57     father[u] = pre;
     58     L[u] = ++tot;
     59     for (int i = head[u]; ~i; i = edge[i].next) {
     60         int v = edge[i].to;
     61         if (v == pre) continue;
     62         dfs(v, u);
     63     }
     64     R[u] = tot;
     65 }
     66 
     67 int tree[maxn];
     68 int lowbit(int x) { return x & -x;}
     69 void update(int x, int val){
     70     while (x <= n) {
     71         tree[x] += val;
     72         x += lowbit(x);
     73     }
     74 }
     75 int sum (int x){
     76     int res = 0;
     77     while (x > 0) {
     78         res += tree[x];
     79         x -= lowbit(x);
     80     }
     81     return res;
     82 }
     83 int query (int x,int y){
     84     int LCA = lca(x, y);
     85     return sum(L[x]) + sum(L[y]) - sum(L[LCA]) - sum(L[father[LCA]]);
     86 }
     87 
     88 int add(int x, int v){
     89     update(L[x], v);
     90     update(R[x] + 1, -v);
     91 }
     92 
     93 int main(){
     94     init_lg();
     95     build();
     96     dfs(1, 0);
     97     dfs_lca(1,0);
     98     string op;
     99     int x, y, w;
    100     while (cin >> op) {
    101         if (op == "Q") {// 输入Q x y表示查询编号为x和y的点的所在链权值和 Add x w表示在x节点上加上w的权值
    102             cin >> x >> y;
    103             cout << query(x, y) << endl;
    104         } else {
    105             cin >> x >> w;
    106             add(x, w);
    107         } 
    108     }
    109     return 0;
    110 }
    111 /*
    112 input : 
    113 Add 5 2
    114 Q 9 2
    115 Q 2 5
    116 Add 2 1
    117 Add 1 3
    118 Add 12 10
    119 Q 15 3
    120 Q 10 3
    121 output :
    122 2
    123 2
    124 10
    125 6 
    126 */

    5.子树修改,单点查询

    修改节点x的子树权值,在dfs序上就是区间修改,单点权值查询就是单点查询。

    区间修改,单点查询问题:树状数组或线段树即可;

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 
     6 const int n = 15;
     7 const int maxn = 1010;
     8 struct E{
     9     int to,next;
    10 }edge[maxn];
    11 int head[maxn], cnt;
    12 int t[maxn];
    13 inline void addedge(int u,int v){
    14     edge[cnt] = (E){v,head[u]};
    15     head[u] = cnt++;
    16     edge[cnt] = (E){u,head[v]};
    17     head[v] = cnt++;
    18 }
    19 void build(){
    20     memset(head, -1, sizeof head);
    21     int tmp[28] = {1,2,1,3,2,4,2,5,2,6,3,7,3,8,5,9,5,10,7,11,7,12,12,13,12,14,12,15};
    22     for (int i = 0; i < 14*2; i+=2){
    23         addedge(tmp[i],tmp[i+1]);
    24     }
    25 }
    26 
    27 
    28 int L[maxn], R[maxn], tot; //l[pos]表示子树的根(编号为pos的子树的dfs序号) R[pos]表示子树结尾的点 L[pos] ~ R[pos]表示以pos为根的子树 
    29 void dfs(int u,int pre){
    30     L[u] = ++tot;
    31     for (int i = head[u]; ~i; i = edge[i].next){
    32         int v = edge[i].to;
    33         if (v == pre) continue;
    34         dfs(v,u);
    35     }
    36     R[u] = tot;
    37 }
    38 
    39 
    40 int tree[maxn];
    41 int lowbit(int x){return x & -x;}
    42 int add(int x,int w){
    43     while (x <= n){
    44         tree[x] += w;
    45         x += lowbit(x);
    46     }
    47 }//对每个节点x加上w 
    48 int sum(int x){
    49     int res = 0;
    50     while (x > 0){
    51         res += tree[x];
    52         x -= lowbit(x);
    53     }
    54     return res;
    55 }
    56 
    57 void update (int x,int val) {
    58     add(L[x], val);
    59     add(R[x]+1, -val);
    60 }
    61 
    62 int main(){
    63     build();
    64     dfs(1,-1);
    65     string op; // 输入Q x表示查询编号为x的权值 Add x w表示在编号为x的子树里加上w的权值 
    66     int x, w;
    67     while (cin >> op){
    68         if (op == "Q"){
    69             cin >> x;
    70             cout << sum(L[x]) << endl;
    71         } else {
    72             cin >> x >> w;
    73             update(x, w);
    74         }
    75     }
    76     return 0;
    77 }
    78 /*
    79 input : 
    80 Add 2 1
    81 Add 3 2
    82 Q 5
    83 Q 10
    84 Q 8
    85 Q 12
    86 Q 15
    87 Add 1 100
    88 Q 4
    89 Q 11 
    90 output : 
    91 1
    92 1
    93 2
    94 2
    95 2
    96 101
    97 102
    98 */

    6.子树修改,子树和查询

    题目等价与区间修改,区间查询问题。用树状数组或线段树即可。

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 
     6 const int n = 15;
     7 const int maxn = 1010;
     8 struct E{
     9     int to,next;
    10 }edge[maxn];
    11 int head[maxn], cnt;
    12 int t[maxn];
    13 inline void addedge(int u,int v){
    14     edge[cnt] = (E){v,head[u]};
    15     head[u] = cnt++;
    16     edge[cnt] = (E){u,head[v]};
    17     head[v] = cnt++;
    18 }
    19 void build(){
    20     memset(head, -1, sizeof head);
    21     int tmp[28] = {1,2,1,3,2,4,2,5,2,6,3,7,3,8,5,9,5,10,7,11,7,12,12,13,12,14,12,15};
    22     for (int i = 0; i < 14*2; i+=2){
    23         addedge(tmp[i],tmp[i+1]);
    24     }
    25 }
    26 
    27 
    28 int L[maxn], R[maxn], tot; //l[pos]表示子树的根(编号为pos的子树的dfs序号) R[pos]表示子树结尾的点 L[pos] ~ R[pos]表示以pos为根的子树 
    29 void dfs(int u,int pre){
    30     L[u] = ++tot;
    31     for (int i = head[u]; ~i; i = edge[i].next){
    32         int v = edge[i].to;
    33         if (v == pre) continue;
    34         dfs(v,u);
    35     }
    36     R[u] = tot;
    37 }
    38 
    39 int sum1[maxn], sum2[maxn];
    40 void add(int p, int x){
    41     for(int i = p; i <= n; i += i & -i)
    42         sum1[i] += x, sum2[i] += x * p;
    43 }
    44 void range_add(int l, int r, int x){
    45     add(l, x), add(r + 1, -x);
    46 }
    47 int ask(int p){
    48     int res = 0;
    49     for(int i = p; i; i -= i & -i)
    50         res += (p + 1) * sum1[i] - sum2[i];
    51     return res;
    52 }
    53 int range_ask(int l, int r){
    54     return ask(r) - ask(l - 1);
    55 }
    56 
    57 int main(){
    58     build();
    59     dfs(1,-1);
    60     string op; // 输入Q x表示查询编号为x的权值 Add x w表示在编号为x的子树里加上w的权值 
    61     int x, w;
    62     while (cin >> op){
    63         if (op == "Q"){
    64             cin >> x;
    65             cout << range_ask(L[x], R[x]) << endl;
    66         } else {
    67             cin >> x >> w;
    68             range_add(L[x], R[x], w);
    69         }
    70     }
    71     return 0;
    72 }
    73 /*
    74 input : 
    75 Add 2 1
    76 Q 1
    77 Add 3 1
    78 Q 1
    79 Q 5
    80 Add 10 100
    81 Q 5
    82 output : 
    83 6
    84 14
    85 3
    86 103
    87 */

     7. 对节点X的子树所有节点加上一个值W, 查询X到Y的路径上所有点的权值和
    同问题4把路径上求和转化为四个点到根节点的和
    X到根节点的和 + Y到根节点的和 - LCA(x, y)到根节点的和 - parent(LCA(x,y)) 到根节点的
    再用刷漆只更新子树.
    修改一点A, 查询某点B到根节点时, 只有B在A的子树内, A对B才有贡献.
    贡献为W * (dep[B] - dep[A] + 1) => W * (1 - dep[A]) + W * dep[B]
    和第三题一样, 用两个sum1,sum2维护 W *(dep[A] + 1),和W.
    最后答案就是sum2*dep[B]-sum1.

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 const int n = 15;
      4 const int maxn = 1010;
      5 
      6 const int lca_maxn = 1010;
      7 const int tree_deep = 25;
      8 int fa[lca_maxn][tree_deep];
      9 int dep[lca_maxn], lg[lca_maxn];
     10 
     11 void init_lg(){
     12     for(int i = 1; i <= n; ++i) //log_2(i)+1
     13     lg[i] = lg[i-1] + (1 << lg[i-1] == i);
     14 }
     15 
     16 struct E{
     17     int to,next;
     18 }edge[maxn];
     19 int head[maxn], cnt;
     20 int t[maxn];
     21 inline void addedge(int u,int v){
     22     edge[cnt] = (E){v,head[u]};
     23     head[u] = cnt++;
     24     edge[cnt] = (E){u,head[v]};
     25     head[v] = cnt++;
     26 }
     27 void build(){
     28     memset(head, -1, sizeof head);
     29     int tmp[28] = {1,2,1,3,2,4,2,5,2,6,3,7,3,8,5,9,5,10,7,11,7,12,12,13,12,14,12,15};
     30     for (int i = 0; i < 14*2; i+=2){
     31         addedge(tmp[i],tmp[i+1]);
     32     }
     33 }
     34 
     35 
     36 void dfs_lca(int u,int pre){
     37     fa[u][0] = pre, dep[u] = dep[pre] + 1;
     38     for (register int i = 1; i <= lg[dep[u]]; ++i){
     39         fa[u][i] = fa[fa[u][i-1]][i-1];
     40     }
     41     for (register int i = head[u]; ~i; i = edge[i].next){
     42         int v = edge[i].to; if (v != pre) dfs_lca(v,u);
     43     }
     44 }
     45 int lca(int x, int y){
     46     if (dep[x] < dep[y]) swap(x, y);
     47     while (dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];
     48     if (x == y) return x;
     49     for (register int i = lg[dep[x] - 1]; i >= 0; --i){
     50         if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
     51     }
     52     return fa[x][0];
     53 }
     54 
     55 int L[maxn], R[maxn], tot, father[maxn];
     56 int dfs(int u, int pre){
     57     father[u] = pre;
     58     L[u] = ++tot;
     59     for (int i = head[u]; ~i; i = edge[i].next) {
     60         int v = edge[i].to;
     61         if (v == pre) continue;
     62         dfs(v, u);
     63     }
     64     R[u] = tot;
     65 }
     66 
     67 int tree1[maxn];
     68 int lowbit(int x) { return x & -x;}
     69 void update1(int x, int val){
     70     while (x <= n) {
     71         tree1[x] += val;
     72         x += lowbit(x);
     73     }
     74 }
     75 int sum1 (int x){
     76     int res = 0;
     77     while (x > 0) {
     78         res += tree1[x];
     79         x -= lowbit(x);
     80     }
     81     return res;
     82 }
     83 
     84 int tree2[maxn];
     85 void update2(int x,int val) {
     86     while (x <= n) {
     87         tree2[x] += val;
     88         x += lowbit(x);
     89     }
     90 }
     91 int sum2 (int x){
     92     int res = 0;
     93     while (x > 0){
     94         res += tree2[x];
     95         x -= lowbit(x);
     96     }
     97     return res;
     98 }
     99 int add(int x, int v){
    100     update1(L[x], v);
    101     update2(L[x], (v*(1-dep[x])));
    102     update1(R[x]+1, -v);
    103     update2(R[x]+1, (-v*(1-dep[x])));
    104 }
    105 
    106 int Q(int x) {
    107     return sum2(L[x]) + sum1(L[x]) * dep[x];
    108 }
    109 
    110 int query(int x, int y){
    111     int LCA = lca(x, y);
    112     return Q(x) + Q(y) - Q(LCA) - Q(father[LCA]);
    113 }
    114 
    115 int main(){
    116     init_lg();
    117     build();
    118     dfs(1, 0);
    119     dfs_lca(1,0);
    120     string op;
    121     int x, y, w;
    122     while (cin >> op) {
    123         if (op == "Q") {// 输入Q x y表示查询树链x到y的权值和 add x w表示在x的子树内所有点权值加上w 
    124             cin >> x >> y;
    125             cout << query(x, y) << endl;
    126         } else {
    127             cin >> x >> w;
    128             add(x, w);
    129         } 
    130     }
    131     return 0;
    132 }
    133 /*
    134 input : 
    135 Add 2 1
    136 Q 6 9
    137 Add 1 1
    138 Q 1 15
    139 Q 3 9
    140 Q 2 2
    141 Add 3 2
    142 Q 3 11
    143 output : 
    144 4
    145 5
    146 8
    147 2
    148 9
    149 */
  • 相关阅读:
    [工作积累点滴整理]虚拟化、云计算配置规划<一>
    视频监控——从其他浏览器打开低版本IE方案
    好记性不如烂笔头-nginx安装环境与Linux安装ftp组件
    (阿里巴巴)数据库连接池——Druid (未完持续更新)
    条形码和二维码编码解码工具类源码
    JS防抖与节流函数封装
    根据设备width(375)动态设置font-size
    JS写一个简单日历
    js常用身份校验规则
    list之flex布局写法及禁止橡皮筋效果
  • 原文地址:https://www.cnblogs.com/hznudreamer/p/12688749.html
Copyright © 2020-2023  润新知