• [模板]洛谷T3368 树状数组 模板2


    1.对于区间修改:

    直接修改数组c[],即进行n次add,肯定会TLE;

    于是在此引入一个新数组:addv[],addv[i]指的是以结点i为根的树的所有元素加上addv[i]。

    设将区间[a,b]中每个数加上x,

    则只需自b向左,将相应的addv[]加上x,再自a-1向左,将多修改的结点的addv[]减去x即可。

    2.对于单点查询:

    设查询结点i,则其原值为:

    (以结点i为根的树的所有元素的和)-(此树中除结点i之外的所有节点的和);

    然后从结点i向树根遍历,将遍历到的节点的addv[]值加给之前已计算出的结点i的原值,最终结果就是结点i现在的值。

    代码如下:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<ctime>
     5 #include<cstdlib>
     6 #include<algorithm>
     7 #include<string>
     8 #include<stack>
     9 #include<queue>
    10 #include<vector>
    11 using namespace std;
    12 void add(int,int);
    13 void update(int,int,int);
    14 int query(int);
    15 int c[500010];
    16 int addv[500010];
    17 int n,m;
    18 int i,t;
    19 int f;
    20 int x,y,k;
    21 int main(){
    22     scanf("%d%d",&n,&m);
    23     for(i=1;i<=n;i++){
    24         scanf("%d",&t);
    25         add(i,t);
    26     }
    27     for(i=1;i<=m;i++){
    28         scanf("%d",&f);
    29         if(f==1){
    30             scanf("%d%d%d",&x,&y,&k);
    31             update(x,y,k);
    32         }
    33         else{
    34             scanf("%d",&x);
    35             printf("%d
    ",query(x));
    36         }
    37     }
    38     return 0;
    39 }
    40 void add(int p,int x){
    41     while(p<=n){
    42         c[p]+=x;
    43         p+=p&-p;
    44     }
    45 }
    46 void update(int a,int b,int x){
    47     while(b>=a){     //区间加
    48         addv[b]+=x;
    49         b-=b&-b;
    50     }
    51     a--;
    52     while(a>b){     //区间减
    53         addv[a]-=x;
    54         a-=a&-a;
    55     }
    56 }
    57 int query(int p){
    58     int p1=p-(p&-p);
    59     int p2=p-1;
    60     int t=c[p];
    61     while(p2>p1){
    62         t-=c[p2];
    63         p2-=p2&-p2;
    64     }         //计算结点原值
    65     while(p<=n){
    66         t+=addv[p];
    67         p+=p&-p;
    68     }     //追加addv[]
    69     return t;
    70 }

    6.25更正:

    上面的代码关于结点原值查找部分进行了无用的累赘操作,现更正如下:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<ctime>
     5 #include<cstdlib>
     6 #include<algorithm>
     7 #include<string>
     8 #include<stack>
     9 #include<queue>
    10 #include<vector>
    11 
    12 using namespace std;
    13 
    14 void update(int,int,int);
    15 int query(int);
    16 
    17 int c[500010];
    18 int addv[500010];
    19 
    20 int n,m,i;
    21 int f,x,y,k;
    22 
    23 int main(){
    24     scanf("%d%d",&n,&m);
    25     
    26     for(i=1;i<=n;i++)scanf("%d",&c[i]);
    27     
    28     for(i=1;i<=m;i++){
    29         scanf("%d",&f);
    30         
    31         if(f==1){
    32             scanf("%d%d%d",&x,&y,&k);
    33             update(x,y,k);
    34         }
    35         else{
    36             scanf("%d",&x);
    37             printf("%d
    ",query(x));
    38         }
    39     }
    40     
    41     return 0;
    42 }
    43 
    44 void update(int a,int b,int x){
    45     while(b>=a){
    46         addv[b]+=x;
    47         b-=b&-b;
    48     }
    49     a--;
    50     while(a>b){
    51         addv[a]-=x;
    52         a-=a&-a;
    53     }
    54 }
    55 
    56 int query(int p){
    57     int sum=c[p];
    58     while(p<=n){
    59         sum+=addv[p];
    60         p+=p&-p;
    61     }
    62     return sum;
    63 }
  • 相关阅读:
    搜索文件/目录的shell脚本
    git的编译安装
    linux命令行直接执行MySQL/MariaDB语句查询
    MySQL重置root密码
    图解TCP/IP三次握手
    使用pull命令从Docker Hub仓库中下载镜像到本地
    BZOJ1051 [HAOI2006]受欢迎的牛(Tarjan缩点)
    BZOJ1026 [SCOI2009]windy数(数位DP)
    CERC2017 H Hidden Hierarchy(树+模拟)
    2018icpc徐州网络赛-H Ryuji doesn't want to study(线段树)
  • 原文地址:https://www.cnblogs.com/running-coder-wfh/p/6901437.html
Copyright © 2020-2023  润新知