zoukankan      html  css  js  c++  java
  • 树状数组的认识与模板

    我对树状数组的认识可以参考视频1视频2,每个人的理解不一样,建议去观看大牛的理解,视频1讲的不太深入,但还是推荐先去看视频1,再去看视频2.

    单点修改,区间最大

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    using namespace std;
    const int maxn=300005;
    int h[maxn],a[maxn];
    int n,m;
    int lowbit(int x)
    {
        return x&(-x);
    }
    void update(int x)
    {
        while(x<=n)
        {
            h[x]=a[x];
            for(int i=1;i<lowbit(x);i<<=1)
            h[x]=max(h[x],h[x-i]);
            x+=lowbit(x);
        }
        return ;
    }
    void findans(int begin,int end)
    {
        int ans=0;
        while(end>=begin)
        {
            ans=max(ans,a[end]);
            end--;
            for(;end-lowbit(end)>=begin;end-=lowbit(end))
            ans=max(ans,h[end]);
        }
        
        printf("%d
    ",ans);
        return ;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        while(scanf("%d%d",&n,&m)==2)
        {
            memset(h,0,sizeof(h));
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                update(i);
            }
            for(int i=1;i<=m;i++)
            {
                char c=getchar();
                while(c!='Q'&&c!='U')c=getchar();
                if(c=='U')//update
                {
                    int y,z;
                    scanf("%d%d",&y,&z);
                    a[y]=z;
                    update(y);
                    continue;    
                }
                if(c=='Q')//findans
                {
                    int y,z;
                    scanf("%d%d",&y,&z);
                    findans(y,z);
                    continue;
                }
            }
        }
        
        return 0;
    }
    View Code

    hdu1166(单点修改区间求和)

    #include<bits/stdc++.h>
    #define maxn 111111
    using namespace std;
    int n;
    int c[maxn];
    int b[maxn];
    int lowbit(int x) {
        return x&-x;
    }
    /**单点修改区间求和**/
    /**
    add(x,num);
    sum(r)-sum(l-1);
    每次x号位置修改num
    求lr闭区间的和
    **/
    
    void add(int k,int num) {
        while(k<=n) {
            c[k]+=num;
            k+=lowbit(k);
        }
    }
    int sum(int k) {
        int ans=0;
        while(k) {
            ans+=c[k];
            k-=lowbit(k);
        }
        return ans;
    }
    int main()
    {
        int t;
        int kase=0;
        scanf("%d",&t);
        while(t--) {
            memset(c,0,sizeof c);
            printf("Case %d:
    ",++kase);
            scanf("%d",&n);
            int x,y;
            for(int i=1;i<=n;i++) {
                scanf("%d",&x);
                add(i,x);
            }
            char s[10];
            while(scanf("%s",s)&&strcmp(s,"End")!=0) {
                if(strcmp(s,"Query")==0) {
                    scanf("%d%d",&x,&y);
                    printf("%d
    ",sum(y)-sum(x-1));
                }
                else {
                    if(strcmp(s,"Add")==0) {
                        scanf("%d%d",&x,&y);
                        add(x,y);
                    }
                    else {
                        scanf("%d%d",&x,&y);
                        add(x,-y);
                    }
                }
            }
        }
        return 0;
    }
    View Code

    hdu 1556(区间修改单点求值)

    #include<bits/stdc++.h>
    #define maxn 111111
    using namespace std;
    int n;
    int c[maxn];
    int b[maxn];
    int lowbit(int x) {
        return x&-x;
    }
    /**区间修改单点询问**/
    /**
    add(l-1,-num);add(r,num);
    sum(x);
    每次修改闭区间lr的值,询问x节点的值
    **/
    
    void add(int k,int num) {
        while(k) {
            b[k]+=num;
            k-=lowbit(k);
        }
    }
    int sum(int k) {
        int ans=0;
        while(k<=n) {
            ans+=b[k];
            k+=lowbit(k);
        }
        return ans;
    }
    int main()
    {
         while(scanf("%d",&n)&&(n!=0)) {
            memset(b,0,sizeof b);
            int x,y;
            for(int i=1;i<=n;i++) {
                scanf("%d%d",&x,&y);
                add(x-1,-1);
                add(y,1);
            }
            for(int i=1;i<n;i++) {
                printf("%d ",sum(i));
            }
            printf("%d
    ",sum(n));
         }
    
    
    
    
    
        return 0;
    }
    View Code
    给出一个全0的矩阵,然后一些操作
    0 S:初始化矩阵,维数是S*S,值全为0,这个操作只有最开始出现一次
    1 X Y A:对于矩阵的X,Y坐标增加A
    2 L B R T:询问(L,B)到(R,T)区间内值的总和
    3:结束对这个矩阵的操作
    #include <iostream>
    #include <stdio.h>
    #include <algorithm>
    #include <string.h>
    using namespace std;
    #define MEM(a,x) memset(a,x,sizeof(a))
    #define LL long long
    #define N 2005
    #define INF 0x3f3f3f3f
    #define lowbit(x) (x&-x)
    const int mod = 1e9+7;
    
    int a[N];
    int n,c[N][N],ans[N],x,y;
    
    int sum(int x,int y)
    {
        int ret=0,i,j;
        for(i = x; i>0; i-=lowbit(i))
        {
            for(j = y; j>0; j-=lowbit(j))
            {
                ret+=c[i][j];
            }
        }
        return ret;
    }
    
    void add(int x,int y,int d)
    {
        int i,j;
        for(i = x; i<=n; i+=lowbit(i))
        {
            for(j = y; j<=n; j+=lowbit(j))
            {
                c[i][j]+=d;
            }
        }
    }
    
    int main()
    {
        int i,j,k,op,x,y;
        while(~scanf("%d%d",&i,&n))
        {
            MEM(c,0);
            while(1)
            {
                scanf("%d",&op);
                if(op==3)
                    break;
                if(op==1)
                {
                    scanf("%d%d%d",&x,&y,&k);
                    add(x+1,y+1,k);
                }
                else
                {
                    int l,b,r,t;
                    scanf("%d%d%d%d",&l,&b,&r,&t);
                    l++,b++,r++,t++;
                    printf("%d
    ",sum(r,t)-sum(r,b-1)-sum(l-1,t)+sum(l-1,b-1));
                }
            }
        }
    
        return 0;
    }
    View Code

     

    区间修改,区间和

    理解

    题目描述 Description

    给你N个数,有两种操作:


    1:给区间[a,b]的所有数增加X


    2:询问区间[a,b]的数的和。

    输入描述 Input Description

    第一行一个正整数n,接下来n行n个整数,

     

    再接下来一个正整数Q,每行表示操作的个数,

     

    如果第一个数是1,后接3个正整数,

     

    表示在区间[a,b]内每个数增加X,如果是2,

     

    表示操作2询问区间[a,b]的和是多少。

     

    pascal选手请不要使用readln读入

    输出描述 Output Description

    对于每个询问输出一行一个答案

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<queue>
    #include<set>
    const int MAXN=200000*4;
    using namespace std;
    int lowbit(int x){return x&(-x);}
    int n,Q,opt,x,y;
    long long A[MAXN],C[MAXN],sum[MAXN],z;
    void modifyA(int x,int val){
        while(x<=n){
            A[x]+=val;
            x+=lowbit(x);
        }
    }
    void modifyC(int x,long long val){
        while(x<=n){
            C[x]+=val;
            x+=lowbit(x);
        }
    }
    void update(int from,int to,long long val){
        modifyA(from,val);
        modifyA(to+1,-val);
        modifyC(from,val*from);
        modifyC(to+1,-val*(to+1));
    }
    long long queryA(int loc){
        long long ans=0;
        while(loc){
            ans+=A[loc];
            loc-=lowbit(loc);
        }
        return ans;
    }
    long long queryC(int loc){
        long long ans=0;
        while(loc){
            ans+=C[loc];
            loc-=lowbit(loc);
        }
        return ans;
    }
    long long query(int loc){
        return sum[loc]+(loc+1)*queryA(loc)-queryC(loc);
    }
    long long query(int from,int to){
        return query(to)-query(from-1);
    }
    int main(){
        scanf("%d",&n);
        for(register int i=1;i<=n;i++)scanf("%d",&sum[i]),sum[i]+=sum[i-1];
        scanf("%d",&Q);
        while(Q--){
            scanf("%d%d%d",&opt,&x,&y);
            if(opt==1){
                scanf("%lld",&z);
                update(x,y,z);
            }else{
                printf("%lld
    ",query(x,y));
            }
        }
        return 0;
    }
    View Code

     

  • 相关阅读:
    在简单地形上小车运动轨迹的数学表达(一)
    结尾
    第十四章 多线程编程
    第十五章 进程池与线程池
    第十章 信号
    第十一章 定时器
    第十三章 多进程编程
    第八章 高性能服务器程序框架
    KMP 专场 POJ2752
    约瑟夫问题 双链表实现
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9111692.html
Copyright © 2011-2022 走看看