• HLJU 1188 Matrix (二维树状数组)


    Matrix

    Time Limit: 4 Sec  Memory Limit: 128 MB

    Description

    给定一个1000*1000的二维矩阵,初始矩阵中每一个数都为1,然后为矩阵有4种操作.

    S x1 y1 x2 y2:计算(x1,y1)、(x2,y2)围成的矩阵内全部元素的和。

    A x y v:将(x,y)添加v

    D x y v:将(x,y)降低v

    M x1 y1 x2 y2 v:将(x1,y1)元素中的v转移到(x2,y2)中去。

    全部操作数都为正数。

    若某一操作将矩阵中元素降到1下面,一律按1处理。

    x,y从0開始编号。

    Input

     第一行一个数t,代表例子个数:

    每组例子第一行一个数m,代表m次操作,m<100000

    接下来m行代表m次操作

    Output

     每组例子输出一个

    Case i:

    i代表第i个例子

     对于每个操作S,输出一行,代表计算结果。

    全部结果均不会超过int范围

    Sample Input

    1
    4
    A 1 1 1
    M 1 1 2 2 1
    D 2 2 1
    S 1 1 2 2

    Sample Output

    Case 1:
    4



    解题思路:非常明显的就是一个非常典型的二维树状数组问题,树状数组部分全然就是模板,仅仅是要在详细解决实际问题的时候,有点技巧。最開始见到这题的时候,我马上想到了曾经切的楼教主出的Matrix,感觉非常相似。然后就直接搞了,后来发现開始,要初始化树状数组的c数组,由于矩阵的初值均为1。就用了两层循环。一个一个调用update()。结果居然超时了。

    。然后又在其它地方优化了,还是超时。。。

    就想了个办法。直接把c数组所有初始化为0。这样就不用一次次的去调用update()了(由于c要存的是他前面的和,如今全为0,和当然也为0了),然后在求区域和的时候。直接加上那个区间里的节点数(由于本来的矩阵中应该所有初始化为1的,可是我開始全初始化为0了。就把每一个节点都少了1,节点数也就是区间的面积)就可以。

    还有就是要求保证原矩阵元素在操作之后不能小于1。详细能够先算出当前位置的元素值, 在操作之前把操作的数e改动。然后直接运行操作就可以。这里还学到了一个求当前位置元素的方法,直接用区域求和函数,对当前点求和。即map[a][b] = getsum( a, b, a, b ). 详见代码


    楼教主的Matrix 见:http://blog.csdn.net/u013446688/article/details/38194977



    AC代码:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int maxn = 1002;
    
    #define lowbit(x)	x & (-x)       //lowbit函数            
    
    int c[maxn][maxn];                     //树状数组的c数组
    
    inline int update(int x, int y, int d){      //update函数 
    	int i, j;
    	for(i=x; i<=1000; i+=lowbit(i))
    		for(j=y; j<=1000; j+=lowbit(j))
    			c[i][j] += d;
    }
    
    
    inline int sum(int x, int y){         //sum函数 
    	int ans = 0;
    	int i, j;
    	for(i=x; i>0; i-=lowbit(i))
    		for(j=y; j>0; j-=lowbit(j))
    			ans += c[i][j];
    	return ans;
    }
    
    int getsum(int x1, int y1, int x2, int y2){       //区域求和
    	return  sum(x2, y2) - sum(x1-1, y2) - sum(x2, y1-1) + sum(x1-1, y1-1);
    }
    
    int main(){
    //	freopen("in.txt","r",stdin);
    	int T, m ,a, b, cc, d, e;
    	string p;
    	scanf("%d", &T);
    	for(int t=1; t<=T; t++){
    		scanf("%d", &m);
    		printf("Case %d:
    ", t);
    		memset(c, 0, sizeof(c));
    		while(m--){
    			cin>>p;
    			if(p[0] == 'A'){
    				scanf("%d%d%d", &a, &b, &e);
    				a++; b++;
    				update(a, b, e);
    			}
    			else if(p[0] == 'D'){
    				scanf("%d%d%d", &a, &b, &e);
    				a++; b++;
    				int k = getsum(a, b, a, b);      //求当前位置的元素的值
    				if(k - e < 0)  e = k;            //改动e, 保证操作之后元素不小于1
    				update(a, b, -e);
    			}
    			else if(p[0] == 'M'){
    				scanf("%d%d%d%d%d", &a, &b, &cc, &d, &e);
    				a++; b++; cc++; d++;
    				int k = getsum(a, b, a, b);      //同上
    				if(k - e < 0)   e = k;
    				update(a, b, -e);
    
    				update(cc, d, e);
    			}
    			else{
    				scanf("%d%d%d%d", &a, &b, &cc, &d);
    				a++; b++; cc++; d++;
    				if(cc < a)  swap(a, cc);
    				if(d < b)  swap(b, d);
    				int ans = getsum(a, b, cc, d) + (cc-a+1)*(d-b+1);    //求矩阵区域和
    				printf("%d
    ",ans);
    			}
    		}
    	}
    	return 0;
    }
    


  • 相关阅读:
    MySQL 事务 清明
    ElasticSearch增删改查
    WinDbg常用命令系列内存查看d*
    WinDbg常用命令系列内存数据显示和对应符号显示d*s(dds、dps、dqs)
    WinDbg常用命令系列!heap
    WinDbg !teb
    Nodejs Stream(流)
    Nodejs 回调函数
    Vertx 简单介绍
    创建第一个应用Nodejs应用
  • 原文地址:https://www.cnblogs.com/clnchanpin/p/6898511.html
Copyright © 2020-2023  润新知