POJ1195Mobile phones (从二维树状数组到cdq分治)
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 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
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分治)的更多相关文章
- 【 HDU - 4456 】Crowd (二维树状数组、cdq分治)
BUPT2017 wintertraining(15) #5A HDU 4456 题意 给你一个n行n列的格子,一开始每个格子值都是0.有M个操作,p=1为第一种操作,给格子(x,y)增加z.p=2为 ...
- poj 1195:Mobile phones(二维树状数组,矩阵求和)
Mobile phones Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 14489 Accepted: 6735 De ...
- (简单) POJ 1195 Mobile phones,二维树状数组。
Description Suppose that the fourth generation mobile phone base stations in the Tampere area operat ...
- POJ 1195 Mobile phones (二维树状数组)
Description Suppose that the fourth generation mobile phone base stations in the Tampere area operat ...
- POJ 1195 Mobile phones【二维树状数组】
<题目链接> 题目大意: 一个由数字构成的大矩阵,开始是全0,能进行两种操作1) 对矩阵里的某个数加上一个整数(可正可负)2) 查询某个子矩阵里所有数字的和要求对每次查询,输出结果 解题分 ...
- POJ-2155:Matrix(二维树状数祖)
Matrix Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 31892 Accepted: 11594 Descript ...
- POJ_1195 Mobile phones 【二维树状数组】
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u013912596/article/details/33802561 题目链接:id=1195&qu ...
- POJ 1195 Mobile phones(二维树状数组)
Mobile phones Time Limit: 5000MS Mem ...
- POJ 1195 Mobile phones (二维树状数组或线段树)
偶然发现这题还没A掉............速速解决了............. 树状数组和线段树比较下,线段树是在是太冗余了,以后能用树状数组还是尽量用......... #include < ...
随机推荐
- HDU 3416
Marriage Match IV Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- 开发ActiveX控件调用另一个ActiveX系列3——ActiveX调用另一个ActiveX
终于进入正题了,怎样在ActiveX中调用另一个ActiveX.我们的项目需要调用华视电子身份证识别仪的ActiveX控件 在这里有很多识别仪ActiveX插件下载:http://www.idukaq ...
- android开发系列之ContentObserver
在这篇博客里面我想要分享一下自己最近在项目里面遇到一个比较好的数据同步解决方案,首先让我们先来看看该方案的应用场景:我们在客户端本地利用数据库缓存了一些数据,当我们检测到数据库里面的数据发生变化的时候 ...
- ck-reset css(2016/5/13)
/**rest by 2016/05/04 */ * {box-sizing: border-box;} *:before,*:after {box-sizing: border-box;} body ...
- 软件工程第2次作业——Visual Studio 2017下基于C/C++的VSTS单元测试实践
Write one minute, test all day long. 环境确定 IDE:Microsoft Visual Studio 2017 Community 语言:C++ 单元测试工具:V ...
- Java异常 - Exception总结
这篇blog总结的比较详细了. 如下图所示,在Java中所有异常的基类均为Throwable类.有两个子类,分别为Exception和Error.其中Error主要由JVM处理,比如OutOfMemo ...
- PHP、AJAX综合练习(增、删、改、查、分页、模糊查询)
先来几张效果图 主页面分页显示: 关键字查询,关键字描红 添加数组,弹出窗口,点击保存,再不刷新页面的同时添加到网页数据 修改界面:弹出窗口,文本框中保留点击的车辆的原始信息 主页面代码 <me ...
- 关于 Delphi 中流的使用(7) 压缩与解压缩(TCompressionStream、TDecompressionStream)
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, For ...
- EasyNVR+EasyDSS实现简单套路的RTMP、微信直播、录像、回放方案
安防领域HLS直播问题探讨 近期外出交流比较多,在之前的一篇博客<一种流量成本节省60%以上的手机直播微信直播H5直播幼儿园直播方案>我们说到了一种模式,就是当我们在做最近火热的幼儿园直播 ...
- Hadoop实战-Flume之Source regex_filter(十三)
a1.sources = r1 a1.sinks = k1 a1.channels = c1 # Describe/configure the source a1.sources.r1.type = ...