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

题目:二维平面上单点加值操作,矩形区间求和操作。

  • 显然这个数据可以用二维树状数组秒

//poj1195树状数组
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=;
int sum[maxn][maxn],N;
int lowbit(int x) { return x&(-x); }
void add(int x,int y,int val)
{
for(int i=x;i<=N;i+=lowbit(i))
for(int j=y;j<=N;j+=lowbit(j))
sum[i][j]+=val;
}
int query(int x,int y)
{
int res=;
for(int i=x;i;i-=lowbit(i))
for(int j=y;j;j-=lowbit(j))
res+=sum[i][j];
return res;
}
int main()
{
int opt,a,b,x,y,val;
while(~scanf("%d",&opt)){
scanf("%d",&N);
memset(sum,,sizeof(sum));
while(scanf("%d",&opt)){
if(opt==) break;
if(opt==){
scanf("%d%d%d",&x,&y,&val);
add(x+,y+,val);
}
else{
scanf("%d%d%d%d",&x,&y,&a,&b);
printf("%d\n",query(a+,b+)+query(x,y)-query(a+,y)-query(x,b+));
}
}
} return ;
}
  • 但如果操作不变,二维平面变大,空间不够时,cdq分治就来了。

首先看下面之前,先回顾一下上面的题,二维树状树组可以做,复杂度为(nlg2n),只是空间变大后不行。此题引用cdq分治是为了降二维树状数组为一维。(避免读者误以为cdq分治优化的是复杂度,其实复杂度没有降低。)

nmphy自诉:
1,为了描述,这里假设分治[l,r]部分时,处理[l,mid]的增加对[mid+1,r]的影响叫做“合并”过程。
2,以下的l,mid,r均是指第几个操作,即按时间排序后是第几个操作,而不是x坐标或者y坐标,不要搞混淆。
我们假设有q个操作(即按时间排序),现在在解决[l,r]这几个操作。
可以肯定:当前合并过程中[mid+,r]的增加的值全部来自于[l,mid]。
为什么呢?l之前增加的值对[mid+1,r]的影响呢呢?[mid+,R]内部操作增加的值对内部后面的影响呢?
仔细一看,l之前增加的值在更大的分治里面(即[l,r]属于[L,R],假设[L,R]=[L,mid]+[l,r],那么l之前的[L,mid]部分就在这里合并处理);
而[mid+,r]增加的值在更新的分治里(即[mid+,(mid++r)/],[(mid++r)/+,r])。
从而保证了前面的增加对后面的询问都被考虑到。
但是[l,mid]对[mid+,r]处理时,增加值使用了一次;合并后[l,r]对[r+,r]处理时,显然[l,mid]的增加值又使用了一次。
所以在处理完内部后,还得减去增加值

上面有点乱的话自己来问我,我觉得理解上面这段话还是很重要的!

所谓cdq分治,就是分治所有操作,计算[l,mid]中的修改对[mid+,r]中的询问的影响。
无法理解的同学可以借助归并排序的思想思考。
抄袭别人讲以上的话吧
、T(n)=2T(n/)+O(kn)的解是T(n)=O(kn log n)
、T(n)=2T(n/)+O(kn log n)的解是T(n)=O(kn log^ n)
、T(n)=2T(n/)+O(k)的解是T(n)=O(kn)

所以cdq分治的复杂度也可以简单的算出来了。
cdq能处理的题目必须满足:、允许离线 、前面的修改对后面的影响很容易算出来 比如说这一题
在[l,mid]部分的修改按x排序从小到大加进一个树状数组里,不断更新对[mid+,r]的影响。
复杂度就是第二种计算方式,可就是O(q log^ w)

因为我们从下向上扫描,所以不需要记录y轴方向的树状数组,只需要跟新x方向即可。

CDQ分治中,首先按x来排序,对t这个维度进行分治。
那么t<=mid的更新操作都能影响到t'>=mid+1的查询结果。
所以在CDQ(l,r)中,按照x从小到大扫一遍所有操作,遇到更新操作就在树状数组上插入y值(y值离散过),
遇到查询操作就给该操作的结果加上树状数组上查询到的sum(,y)的值。
接下来用类似归并排序的方法,把t<=mid的操作都放到数组左半部分,t>=mid+1的操作都放到右半部分
这么做之后两半部分的y依然是有序的,就可以递归处理两半部分之间的更新操作对查询操作产生的影响了。
你瞅啥?
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lowbit(x) ((x)&(-(x)))
const int Maxn=;
int x1[Maxn],x2[Maxn],y1[Maxn],y2[Maxn],tr[Maxn];
int a[Maxn],b[Maxn],c[Maxn],opt[Maxn],ans[Maxn];
int n,m,s,w,i;
struct arr{
int x,l,r,k,c;
bool operator <(const arr &a) const { return x<a.x; }
}qk[Maxn];
struct ad{
int x,y,w;
bool operator <(const ad &a) const { return x<a.x; }
}g[Maxn];
int query(int x){
int ret=;
for (int i=x;i>;i-=lowbit(i)) ret+=tr[i];
return ret;
}
void add(int x,int s){
for(int i=x;i<=m;i+=lowbit(i)) tr[i]+=s;
}
void combine(int l,int r)
{
int mid=(l+r)>>,t=,tt=,i,j;
for(i=mid+;i<=r;i++)
if(opt[i]==){
qk[++t]=(arr){x1[i]-, y1[i], y2[i], i, };
qk[++t]=(arr){x2[i], y1[i], y2[i], i, };
}
sort(qk+,qk+t+); //按x排序
for(i=l;i<=mid;i++)
if(opt[i]==) g[++tt]=(ad){x1[i],y1[i],x2[i]};
sort(g+,g+tt+);
for(i=,j=;i<=tt;i++){
while(j<=t&&qk[j].x<g[i].x){
if (qk[j].c==) ans[qk[j].k]-=query(qk[j].r)-query(qk[j].l-);
else ans[qk[j].k]+=query(qk[j].r)-query(qk[j].l-);
j++;
} add(g[i].y,g[i].w);
}
while(j<=t){
if(qk[j].c==) ans[qk[j].k]-=query(qk[j].r)-query(qk[j].l-);
else ans[qk[j].k]+=query(qk[j].r)-query(qk[j].l-);
j++;
}
for(i=;i<=tt;i++) add(g[i].y,-g[i].w);//减去增加值
}
void cdq(int l,int r){
if(l==r) return;
int mid=(l+r)>>;
cdq(l,mid);
combine(l,r); //前+前半截对后半截的影响+后
cdq(mid+,r);
}
int main(){
scanf("%d%d",&s,&w); n=; //s是初始值,此题为0
while (true){
scanf("%d",&opt[n]);
if(opt[n]==||opt[n]==) break;
if(opt[n]==){
scanf("%d%d%d",&x1[n],&y1[n],&x2[n]);
c[++m]=y1[n];
}else
if(opt[n]==){
scanf("%d%d%d%d",&x1[n],&y1[n],&x2[n],&y2[n]);
ans[n]+=s*(x2[n]-x1[n]+)*(y2[n]-y1[n]+);
c[++m]=y1[n]; c[++m]=y2[n]; //c是复制y坐标来离散
} n++;
}
sort(c+,c+m+); //按y排序
m=unique(c+,c+m+)-(c+); //离散
for(i=;i<n;i++){
y1[i]=lower_bound(c+,c+m+,y1[i])-c;
if(opt[i]==) y2[i]=lower_bound(c+,c+m+,y2[i])-c;
} cdq(,--n);
for(i=;i<=n;i++) if(opt[i]==) printf("%d\n",ans[i]);
return ;
}

园丁的烦恼 SHOI2007 BZOJ 1935

  【模板】树状数组 1 luogu P3374

  Mokia BZOJ 1176

  陌上花开 BZOJ 3262

  简单题BZOJ 2683

  动态逆序对 CQOI2011 BZOJ 3295

POJ1195Mobile phones (从二维树状数组到cdq分治)的更多相关文章

  1. 【 HDU - 4456 】Crowd (二维树状数组、cdq分治)

    BUPT2017 wintertraining(15) #5A HDU 4456 题意 给你一个n行n列的格子,一开始每个格子值都是0.有M个操作,p=1为第一种操作,给格子(x,y)增加z.p=2为 ...

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

    Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14489   Accepted: 6735 De ...

  3. (简单) POJ 1195 Mobile phones,二维树状数组。

    Description Suppose that the fourth generation mobile phone base stations in the Tampere area operat ...

  4. POJ 1195 Mobile phones (二维树状数组)

    Description Suppose that the fourth generation mobile phone base stations in the Tampere area operat ...

  5. POJ 1195 Mobile phones【二维树状数组】

    <题目链接> 题目大意: 一个由数字构成的大矩阵,开始是全0,能进行两种操作1) 对矩阵里的某个数加上一个整数(可正可负)2) 查询某个子矩阵里所有数字的和要求对每次查询,输出结果 解题分 ...

  6. POJ-2155:Matrix(二维树状数祖)

    Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 31892   Accepted: 11594 Descript ...

  7. POJ_1195 Mobile phones 【二维树状数组】

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u013912596/article/details/33802561 题目链接:id=1195&qu ...

  8. POJ 1195 Mobile phones(二维树状数组)

                                                                  Mobile phones Time Limit: 5000MS   Mem ...

  9. POJ 1195 Mobile phones (二维树状数组或线段树)

    偶然发现这题还没A掉............速速解决了............. 树状数组和线段树比较下,线段树是在是太冗余了,以后能用树状数组还是尽量用......... #include < ...

随机推荐

  1. HDU 小明系列故事——师兄帮帮忙 高速幂

    小明系列故事--师兄帮帮忙 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) To ...

  2. CentOS 6.5语言包裁剪

    https://www.ibm.com/developerworks/cn/linux/l-cn-linuxglb/ 浅析 Linux 的国际化与本地化机制 Linux 是一个国际化的操作系统,它的工 ...

  3. Lua学习二----------Lua的基本语法

    © 版权声明:本文为博主原创文章,转载请注明出处 Lua基本语法: 1.--表示单行注释 2.--[[--]]表示多行注释 3.Lua区分大小写 4.Lua中变量默认是全局变量,除非用local显式声 ...

  4. &lt;LeetCode OJ&gt; 141 / 142 Linked List Cycle(I / II)

    Given a linked list, determine if it has a cycle in it. Follow up: Can you solve it without using ex ...

  5. 目标跟踪之camshift---opencv中meanshift和camshift例子的应用

    在这一节中,主要讲目标跟踪的一个重要的算法Camshift,因为它是连续自使用的meanShift,所以这2个函数opencv中都有,且都很重要.为了让大家先达到一个感性认识.这节主要是看懂和运行op ...

  6. struts2的 defalut-action-ref 的使用

    这个配置的用法有值得注意的地方,所以才记录下来: 一般default-action-refer配置的action是在浏览器中输入的网址只输入到项目时或输入错误的action时 所进入的action,一 ...

  7. php计算数组的维数

    function array_dim($arr){ if(!is_array($arr)) return 0; else{ $max1 = 0; foreach($arr as $item1){ $t ...

  8. 推荐20个非常有帮助的web前端开发教程

    1. CSS Vocabulary 一个伟大的指向和点击的小应用程序,让你加高速度掌握 CSS 语法的各个不同部分,学习各个属性的正确的名称. 2. Liquidapsive 一个简单的信息化布局.通 ...

  9. 《转》使用nginx和php实时产生缩略图

    在做自动静态化的时候,突然想到下面这个场景,也给出了解决方法.亲,真的很实用,耐心看下去.     当我从后台上传一个截图之后,480*800的截图之后,当时就没有压缩出320*480的小缩略图.好吧 ...

  10. Java 内存模型及GC原理

    一个优秀Java程序员,必须了解Java内存模型.GC工作原理,以及如何优化GC的性能.与GC进行有限的交互,有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率,才能 ...