呓语 | 杨英明的个人博客

专注于c++、Python,欢迎交流

By

poj 1195:Mobile phones(二维线段树,矩阵求和)

Mobile phones
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 14391   Accepted: 6685

Description

Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The squares form an S * S matrix with the rows and columns numbered from 0 to S-1. Each square contains a base station. The number of active mobile phones inside a square can change because a phone is moved from a square to another or a phone is switched on or off. At times, each base station reports the change in the number of active phones to the main base station along with the row and the column of the matrix. 

Write a program, which receives these reports and answers queries about the current total number of active mobile phones in any rectangle-shaped area. 

Input

The input is read from standard input as integers and the answers to the queries are written to standard output as integers. The input is encoded as follows. Each input comes on a separate line, and consists of one instruction integer and a number of parameter integers according to the following table. 

The values will always be in range, so there is no need to check them. In particular, if A is negative, it can be assumed that it will not reduce the square value below zero. The indexing starts at 0, e.g. for a table of size 4 * 4, we have 0 <= X <= 3 and 0 <= Y <= 3. 

Table size: 1 * 1 <= S * S <= 1024 * 1024 
Cell value V at any time: 0 <= V <= 32767 
Update amount: -32768 <= A <= 32767 
No of instructions in input: 3 <= U <= 60002 
Maximum number of phones in the whole table: M= 2^30 

Output

Your program should not answer anything to lines with an instruction other than 2. If the instruction is 2, then your program is expected to answer the query by writing the answer as a single line containing a single integer to standard output.

Sample Input

0 4
1 1 2 3
2 0 0 2 2 
1 1 1 2
1 1 2 -1
2 1 1 2 3 
3

Sample Output

3
4

Source

 
  二维线段树,矩阵求和,经典题
  这道题用二维树状数组做更快,更省空间,代码更简洁。
  二维树状数组做法见右方链接:poj 1195:Mobile phones(二维树状数组,矩阵求和)
 
  题意
  一个矩阵,初始化为全0。有以下操作:
  1)将 (x,y) 元素加 a。x为行坐标,y为列坐标。
  2)求矩阵 [X,Y] 所有元素的和。该矩阵左上角为[l,b],右下角为[r,t]。
 
  思路
  这道题是一道经典的二维线段树的题,由于是区间求和,所以用二维树状数组也可以实现,而且更快,代码更少。
  二维线段树的实现方法有两种:树套树,四叉树。树套树常用一些。
  这道题的我是用树套树实现。
  二维线段树的每一个节点代表一个矩阵,在这道题里,节点存储的是这个矩阵的元素和,用一个二维数组int tree[][]存储所有不同矩阵的和。
  例:如果矩阵大小为4*4,则tree[1][2]代表,左上角坐标为[1,1],右下角坐标为[4,2]的一个矩阵。1代表1-4这个区间,即第一行到第四行;2代表1的左节点,1-2这个区间,即第一列到第二列。取交集就是这样一个矩阵。
  tree[1][2]的结果就是这个矩阵所有元素的和。
 
  附加一个 c源代码+20组测试数据 的压缩包下载地址:
 
  其加数,求和操作见代码
  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 using namespace std;
  5 
  6 #define MAXN 1100
  7 
  8 int tree[MAXN*3][MAXN*3],s;
  9 
 10 void Add_y(int d,int dy,int L,int R,int y,int a)    //加数列操作
 11 {
 12     tree[d][dy] += a;    //相关矩阵全部加a
 13     
 14     if(L==R){
 15         return ;
 16     }
 17 
 18     int mid = (L+R)>>1;
 19     if(mid>=y)
 20         Add_y(d,dy<<1,L,mid,y,a);
 21     else
 22         Add_y(d,dy<<1|1,mid+1,R,y,a);
 23 }
 24 
 25 void Add_x(int d,int L,int R,int x,int y,int a)        //加数行操作
 26 {
 27     Add_y(d,1,1,s,y,a);    //每一个行块都要更新其对应的列块,这样才能将所有与(x,y)相关的矩阵的值更新
 28     
 29     if(L==R){
 30         return ;
 31     }
 32 
 33     int mid = (L+R)>>1;
 34     if(mid>=x)
 35         Add_x(d<<1,L,mid,x,y,a);
 36     else
 37         Add_x(d<<1|1,mid+1,R,x,y,a);
 38 }
 39 
 40 
 41 int Sum_y(int d,int dy,int L,int R,int b,int t)
 42 {
 43     if(L==b && R==t)    //找到要找的矩阵,输出这个矩阵对应的值
 44         return tree[d][dy];
 45 
 46     //没找到
 47     int mid = (L+R)>>1;
 48     if(mid >= t)
 49         return Sum_y(d,dy<<1,L,mid,b,t);
 50     else if(mid < b)
 51         return Sum_y(d,dy<<1|1,mid+1,R,b,t);
 52     else 
 53         return Sum_y(d,dy<<1,L,mid,b,mid) + Sum_y(d,dy<<1|1,mid+1,R,mid+1,t);
 54 }
 55 
 56 int Sum_x(int d,int L,int R,int l,int r,int b,int t)
 57 {
 58     if(L==l && R==r){    //找到要找的行块,继续查找列块
 59         return Sum_y(d,1,1,s,b,t);
 60     }
 61 
 62     //没找到
 63     int mid = (L+R)>>1;
 64     if(mid >= r)
 65         return Sum_x(d<<1,L,mid,l,r,b,t);
 66     else if(mid < l)
 67         return Sum_x(d<<1|1,mid+1,R,l,r,b,t);
 68     else 
 69         return Sum_x(d<<1,L,mid,l,mid,b,t) + Sum_x(d<<1|1,mid+1,R,mid+1,r,b,t);
 70 }
 71 
 72 int main()
 73 {
 74     int cmd,x,y,a,l,r,b,t;
 75 
 76     while(scanf("%d",&cmd)!=EOF){
 77         switch(cmd){
 78         case 0:    //初始化矩阵
 79             scanf("%d",&s);
 80             memset(tree,0,sizeof(tree));
 81             break;
 82 
 83         case 1:    //加数
 84             scanf("%d%d%d",&x,&y,&a);
 85             Add_x(1,1,s,x+1,y+1,a);
 86             break;
 87 
 88         case 2:    //求矩阵和
 89             scanf("%d%d%d%d",&l,&b,&r,&t);
 90             printf("%d\n",Sum_x(1,1,s,l+1,r+1,b+1,t+1));
 91             break;
 92 
 93         case 3:    //退出程序
 94             return 0;
 95         default:
 96             break;
 97         }
 98     }
 99     return 0;
100 }

 

Freecode : www.cnblogs.com/yym2013

##原创声明 **转载请注明:[呓语](http://www.yangyingming.com) » [poj 1195:Mobile phones(二维线段树,矩阵求和)](http://www.yangyingming.com/article/60)**