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

IOI 2001


  二维线段树,矩阵求和,经典题

  题意

  一个矩阵,初始化为全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组测试数据 的压缩包下载地址:

  http://pan.baidu.com/share/link?shareid=493792&uk=2902487555

  其加数,求和操作见代码

  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

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

时间: 2024-07-28 19:31:21

poj 1195:Mobile phones(二维线段树,矩阵求和,经典题)的相关文章

poj1195 Mobile phones 二维线段树入门

二维线段树就是树套树,线段树套线段树... #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) #define lson l,m,rt<<1 #

poj 1195 Mobile phones(二维数组)

#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int c[1048][1048],n; int lowbit[1048]; 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

POJ 2155 Matrix【二维线段树】

题目大意:给你一个全是0的N*N矩阵,每次有两种操作:1将矩阵中一个子矩阵置反,2.查询某个点是0还是1 思路:裸的二维线段树 #include<iostream>#include<cstdio>#include <math.h>#include<algorithm>#include<string.h>#include<queue>#define MOD 1000003#define maxn 4009#define LL long

poj 1195:Mobile phones(二维树状数组,矩阵求和)

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14489   Accepted: 6735 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The

POJ1195 Mobile phones 【二维线段树】

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14291   Accepted: 6644 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The

POJ1195 Mobile phones 二维树状数组的应用

这题可以用线段树离散化做,用二维树状数组做了一下,不懂得可以看一下这篇文章:http://www.java3z.com/cwbwebhome/article/article1/1369.html?id=4804 题意: 给你一个s*s的正方形区域,先输入一个x,若x==0,则再输入一个s,若x==1,则输入x,y,a,表示矩阵中(x,y)这点的值加上a,若x==2,输入l,b,r,t,代表以左上角的点(l,b)右下角的点(r,t),求这一片矩形内的矩阵元素之和,若x==3则结束此次程序 就是最基

POJ 2155 二维线段树

POJ 2155  二维线段树 思路:二维线段树就是每个节点套一棵线段树的树. 刚开始因为题目是求A[I,J],然后在y查询那直接ans^=Map[i][j]的时候没看懂,后面自己把图画出来了才理解. 因为只有0和1,所以可以用异或来搞,而不需要每次都需要修改. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #incl

POJ 2155 二维线段树 经典的记录所有修改再统一遍历 单点查询

本来是想找一个二维线段树涉及懒惰标记的,一看这个题,区间修改,单点查询,以为是懒惰标记,敲到一半发现这二维线段树就不适合懒惰标记,你更新了某段的某列,但其实其他段的相应列也要打标记,但因为区间不一样,又不好打...也可能是我这是在套用一维线段树的思想,还有更好的二维线段树懒惰标记方法 反正到现在我还没搞定二维线段树的懒惰标记,因为这道题不用懒惰标记,因为是二进制序列,区间修改仅限于翻转操作,那就只要记录每次操作,最后查询的时候从上往下把所有修改都来上一遍,就可以了.就类似于树状数组的第二种用法,

POJ 2155 Matrix (二维线段树)

http://poj.org/problem?id=2155 Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 18143   Accepted: 6813 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. I