• 多维树状数组


    hdu2642

    http://acm.hdu.edu.cn/showproblem.php?pid=2642

    题目大意:

    现在假设天空是一个二维平面(1000*1000)。坐标从(0,0)点开始。现在给出N条信息。

    "B X Y",B为字符,x、y是整数,表示将坐标(x,y)的星星变亮。

    "D XY",D为字符,x、y是整数,表示将坐标(x,y)的星星变暗。

    "Q X1 X2 Y1 Y2",Q是字符,X1、X2、Y1、Y2是整数,表示问有多少颗星星在X1、X2、

    Y1、Y2确定的矩形中。

    思路:

    建立一个二维的树状数组,单点更新,区间求值。其实和一维的差不多。只不过第i个元素变

    为了第x行第y列的元素。更新和求值都是二维维护数组数组。再用一个二维数组Mark[][]表

    示(x、y)处的星星的明暗情况。因为坐标是从(0,0)点开始的,而Lowbit(0) = 0,所以,另

    所有的横纵坐标都加1,使坐标从(1,1)点开始。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int M=1e3+3;
    int a[M][M],vis[M][M];
    int lowbit(int x){
        return x&(-x);
    }
    void update(int x,int y,int c){
        for(int i=x;i<M;i+=lowbit(i))
            for(int j=y;j<M;j+=lowbit(j))
                a[i][j]+=c;
    }
    int sum(int x,int y){
        int ans=0;
        for(int i=x;i>0;i-=lowbit(i))
            for(int j=y;j>0;j-=lowbit(j))
                ans+=a[i][j];
        return ans;
    }
    char s[2];
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            if(s[0]=='Q'){
                int x1,x2,y1,y2;
                scanf("%d%d%d%d",&x1,&x2,&y1,&y2);
                x1++,x2++,y1++,y2++;
                if(x1<x2)
                    swap(x1,x2);
                if(y1<y2)
                    swap(y1,y2);
                printf("%d
    ",sum(x1,y1)+sum(x2-1,y2-1)-sum(x1,y2-1)-sum(x2-1,y1));
            }
            else{
                int x,y;
                scanf("%d%d",&x,&y);
                x++,y++;
                if(s[0]=='B'){
                    if(!vis[x][y]){
                        vis[x][y]=1;
                        update(x,y,1);
                    }
                }
                else{
                    if(vis[x][y]){
                        vis[x][y]=0;
                        update(x,y,-1);
                    }
                }
            }
        }
        return 0;
    }
    View Code

    三维数状数组修改板子:

     if(x==1)
            {
                int x1,y1,z1,x2,y2,z2,w;
                cin>>x1>>y1>>z1>>x2>>y2>>z2>>w;
                 update(x1,y1,z1,w); 
                 update(x1,y2+1,z1,-w); 
                 update(x2+1,y1,z1,-w); 
                 update(x2+1,y2+1,z1,w); 
    
                 update(x1,y1,z2+1,-w); 
                 update(x1,y2+1,z2+1,w); 
                 update(x2+1,y1,z2+1,w); 
                 update(x2+1,y2+1,z2+1,-w); 
            }
            if(x==2)
            {
                int x,y,z;
                cin>>x>>y>>z;
                cout<<sum(x,y,z)<<endl;
            }
    

      

    hdu

    http://acm.hdu.edu.cn/showproblem.php?pid=3584

    思路:

    三维树状数组区间更新、单点查询。更新区间(a,b)时,在 a 和 b+1 处都加1,前边表示增加1,后边是

    抵消加1操作,最后询问时,用Query(x) % 2 即为单点的值(0或1)。三维区间更新,要注意区间的合并会

    重复,所以要利用容斥原理,更新区间(x1,y1,z1)~(x2,y2,z2)时,需要利用容斥原理。更新如下:

    Update(x1,y1,z1); Update(x1,y1,z2+1); Update(x1,y2+1,z1); Update(x1,y2+1,z2+1);

    Update(x2+1,y1,z1); Update(x2+1,y1,z2+1); Update(x2+1,y2+1,z1); Update(x2+1,y2+1,z2+1);

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int M=110;
    int a[M][M][M];
    int n,m;
    int lowbit(int x){
        return x&(-x);
    }
    void update(int x,int y,int z){
        for(int i=x;i<=n;i+=lowbit(i))
            for(int j=y;j<=n;j+=lowbit(j))
                for(int k=z;k<=n;k+=lowbit(k))
                    a[i][j][k]++;
    }
    int sum(int x,int y,int z){
        int ans=0;
        for(int i=x;i>0;i-=lowbit(i))
            for(int j=y;j>0;j-=lowbit(j))
                for(int k=z;k>0;k-=lowbit(k))
                    ans+=a[i][j][k];
        return ans;
    }
    int main(){
        while(~scanf("%d%d",&n,&m)){
            memset(a,0,sizeof(a));
            while(m--){
                int op;
                scanf("%d",&op);
                int x,y,z,xx,yy,zz;
                if(op==1){
                    scanf("%d%d%d%d%d%d",&x,&y,&z,&xx,&yy,&zz);
                    update(x,y,z);
                    update(xx+1,y,z);
                    update(x,yy+1,z);
                    update(x,y,zz+1);
                    update(xx+1,yy+1,z);
                    update(xx+1,y,zz+1);
                    update(x,yy+1,zz+1);
                    update(xx+1,yy+1,zz+1);
                }
                else{
                    scanf("%d%d%d",&x,&y,&z);
                    printf("%d
    ",sum(x,y,z)%2);
                }
            }
        }
        return 0;
    }
    View Code

     http://poj.org/problem?id=2299

    题意:给序列,只能相邻交换,问交换次数最小数;

    分析:1、问题转换为逆序对数

          2、题目给定的序列数太大,离散化;

       3、考虑用树状数组

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    
    const int M=5e5+5;
    int cnt[M],z[M],a[M];
    int n;
    int lowbit(int x){
        return x&(-x);
    }
    void update(int x){
        while(x<=n)
            cnt[x]++,x+=lowbit(x);
    }
    int sum(int x){
        int ans=0;
        while(x)
            ans+=cnt[x],x-=lowbit(x);
        return ans;
    }
    int main(){
    
        while(~scanf("%d",&n)&&n){
            memset(cnt,0,sizeof(cnt));
            for(int i=0;i<n;i++)
                scanf("%d",&a[i]),z[i]=a[i];
            sort(z,z+n);
            ll ans=0;
            for(int i=0;i<n;i++)
                a[i]=lower_bound(z,z+n,a[i])-z+1;
        /*    for(int i=0;i<n;i++)
                cout<<a[i]<<" ";
            cout<<endl;*/ 
            for(int i=0;i<n;i++){
                update(a[i]);
                ans+=i+1-sum(a[i]);
            }
            printf("%I64d
    ",ans);
        }
    
        
        return 0;
    }
    View Code
  • 相关阅读:
    webapp之路--meta标签format-detection、apple-mobile-web-app-capable
    js 进行年月日时间差计算
    JS手机邮箱身份证号码的正则验证以及通过身份证号码获取出生年月日
    react setState()方法可以只修改一个对象的部分属性
    js获取当前时间格式YYYY/MM/DD
    提高CSS开发能力的技巧集
    JavaScript专业规则12条
    为什么大型网站前端使用PHP后台逻辑用Java
    Cookie与Session的区别
    2016年JavaScript技术栈展望
  • 原文地址:https://www.cnblogs.com/starve/p/11183231.html
Copyright © 2020-2023  润新知