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 < ...
随机推荐
- 阿里云官方教程 Linux 系统挂载数据盘
适用系统:Linux(Redhat , CentOS,Debian,Ubuntu) * Linux的云服务器数据盘未做分区和格式化,可以根据以下步骤进行分区以及格式化操作. 下面的操作将会把数据盘划 ...
- Spring学习四----------Bean的配置之Bean的配置项及作用域
© 版权声明:本文为博主原创文章,转载请注明出处 Bean的作用域(每个作用域都是在同一个Bean容器中) 1.singleton:单例,指一个Bean容器中只存在一份(默认) 2.prototype ...
- Redis(六):java里常用的redis客户端(Jedis和Redisson)
Redis的各种语言客户端列表,请参见Redis Client.其中Java客户端在github上start最高的是Jedis和Redisson.Jedis提供了完整Redis命令,而Redisson ...
- partition by和group by对比
今天大概弄懂了partition by和group by的区别联系. 1. group by是分组函数,partition by是分析函数(然后像sum()等是聚合函数): 2. 在执行顺序上, 以下 ...
- erlang的timer定时器浅析
timer作为其计时器: erlang的计时器timer是通过一个唯一的timer进程实现的,该进程是一个gen_server,用户通过timer:send_after和timer:apply_aft ...
- CentOS搭建git服务器实测
Git 可以使用四种主要的协议来传输数据:本地传输,SSH 协议,Git 协议和 HTTP 协议 1,安装: CentOS/Fedora: yum install git Ubuntu/Debian: ...
- 抽钻石vs中奖门 概率问题
在概率问题中,假设跟着日常经验与感觉走.常常会得到错误的答案.以下"抽钻石"的故事非常可以说明这一点. 题目一:某天电视台举办了这种一个游戏节目.主持人首先拿出三个盒子.已知这三个 ...
- 用canvas合成图片
朋友圈有些分享功能是通过长按图片另存来实现的,就像淘宝内部要分享朋友圈的时候一样,这些图片可以用canvas来合成. 获取了img的dom对象以后,进行base64的转. //加载对象$page.ge ...
- spirng boot资料
这里有个srping boot 各种整合的资料 https://blog.csdn.net/Winter_chen001/article/details/80537829 SpringBoot入门总结 ...
- 【BZOJ4052】[Cerc2013]Magical GCD 乱搞
[BZOJ4052][Cerc2013]Magical GCD Description 给出一个长度在 100 000 以内的正整数序列,大小不超过 10^12. 求一个连续子序列,使得在所有的连续 ...