BZOJ 1176[Balkan2007]Mokia (cdq分治,矩阵加矩阵求和)
BZOJ 1176[Balkan2007]Mokia (cdq分治,矩阵加矩阵求和)
Description
维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.
Input
第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小
接下来每行为一下三种输入之一(不包含引号):
“1 x y a”
“2 x1 y1 x2 y2”
“3”
输入1:你需要把(x,y)(第x行第y列)的格子权值增加a
输入2:你需要求出以左下角为(x1,y1),右上角为(x2,y2)的矩阵内所有格子的权值和,并输出
输入3:表示输入结束
Output
对于每个输入2,输出一行,即输入2的答案。
思路:
其实这就是一个在线的矩阵加矩阵求和,而cdq分治可以把二维平面上的在线问题变为三维的离线问题。
在之前学cdq分治时,矩阵加矩阵求和总是不理解怎么用cdq分治解。最近看到这个题,感觉就是个cdq分治板子题,也能练下怎么把在线问题转化为离线问题。(看了题解都看不会,自己无意中想到这不是三维偏序吗O(∩_∩)O
怎么转化为三维偏序问题呢?我们可以把操作的时间戳给加到第三维,而且让第 iii 次操作的查询矩阵分解为四个前缀矩阵的加减法。那么对于每次修改操作有信息(x,y,z)(x,y,z)(x,y,z),代表修改的是坐标(x,y)(x,y)(x,y)坐标,时间戳是zzz。对于每个前缀矩阵有信息(x,y,z)(x,y,z)(x,y,z),即代表右上角坐标为(x,y)(x,y)(x,y),时间戳为z,对于该前缀矩阵此时的增加和,等于所有修改操作(x,y,z)(x,y,z)(x,y,z),满足x′≤x,y′≤y,z′≤zx'\le x,y'\le y,z'\le zx′≤x,y′≤y,z′≤z 的修改的操作值的和。
Cdq(1,n)解决当前区间,那么这些修改,询问的点对 (i,j) 分三类情况,且刚进入时,是按xxx从小到大排序。
注意解决三维偏序时,对第一维排序后必须满足,对于点对小于本身的的一定是在第
- i∈[1,m],j∈[1,m]i\in[1,m],j\in[1,m]i∈[1,m],j∈[1,m],用cdq(l,m)cdq(l,m)cdq(l,m)解决
- i∈[m+1,r],j∈[l+1,r]i\in[m+1,r],j\in[l+1,r]i∈[m+1,r],j∈[l+1,r],用cdq(m+1,r)cdq(m+1,r)cdq(m+1,r)解决
- i∈[l,m],r∈[m+1,r]i\in[l,m],r\in[m+1,r]i∈[l,m],r∈[m+1,r],在当前区间解决,将左右区间的y从小到大排序,对于右边区间的查询操作,统计左区间的所有修改操作的z′≤zz'\le zz′≤z的vvv 贡献和。这部分操作可以用双指针+树状数组优化到O(nlogn)O(nlogn)O(nlogn)
整体时间复杂度为O(nlogn2)O(nlogn^2)O(nlogn2)
代码:
#include <bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int N=2e5+20;
/*
三维偏序,第一维x,第二维y,第三维时间戳d
点分两种:一种修改,一种求和
*/
struct BITtree
{int bt[N];int MXN;int lowbit(int k){return k&-k;}void add(int k,int v){while(k<=MXN){bt[k]+=v;k+=lowbit(k);}}int getpre(int k){int ans=0;while(k){ans+=bt[k];k-=lowbit(k);}return ans;}void en(int k)//销毁 k 路径上的值{while(k<=MXN){bt[k]=0;k+=lowbit(k);}}
}ooo;
struct pnode
{int x,y,z,v;//s为时间戳,f为flag,v为值int k;//询问则表示这是第k个询问,-1代表这是个修改pnode() {}pnode(int x,int y,int z,int v,int k):x(x),y(y),z(z),v(v),k(k) {}
} t[N];
bool cmpx(const pnode & a,const pnode &b)
{if(a.x==b.x) return a.z<b.z;return a.x<b.x;
}
bool cmpy(const pnode & a,const pnode &b)
{return a.y<b.y;
}
int ans[10005];
void cdq(int l,int r)
{if(l==r) return ;int m=l+r>>1;cdq(l,m);cdq(m+1,r);sort(t+l,t+m+1,cmpy);sort(t+m+1,t+r+1,cmpy);int p=l-1;for(int i=m+1;i<=r;++i){while(p<m&&t[p+1].y<=t[i].y) {++p;if(t[p].k==-1)ooo.add(t[p].z,t[p].v);}if(t[i].k!=-1){int sum=ooo.getpre(t[i].z);ans[t[i].k]+=sum*t[i].v;}}for(int i=l;i<=p;++i)if(t[i].k==-1) ooo.en(t[i].z);
}
int main()
{int n,s,tol=0;scanf("%d%d",&s,&n);int qid=0,dfn=0;while(true){int cmd,x,y,xx,yy,a;++dfn;scanf("%d",&cmd);if(cmd==1)//修改{scanf("%d%d%d",&x,&y,&a);t[++tol]=pnode(x,y,dfn,a,-1);}else if(cmd==2){++qid;scanf("%d%d%d%d",&x,&y,&xx,&yy);t[++tol]=pnode(xx,yy,dfn,1,qid);t[++tol]=pnode(xx,y-1,dfn,-1,qid);t[++tol]=pnode(x-1,yy,dfn,-1,qid);t[++tol]=pnode(x-1,y-1,dfn,1,qid);ans[qid]=(xx-x+1)*(yy-y+1)*s;}elsebreak;}ooo.MXN=dfn;sort(t+1,t+tol+1,cmpx);cdq(1,tol);for(int i=1;i<=qid;++i) printf("%d\n",ans[i]);return 0;
}
BZOJ 1176[Balkan2007]Mokia (cdq分治,矩阵加矩阵求和)相关推荐
- BZOJ 1176: [Balkan2007]Mokia( CDQ分治 + 树状数组 )
考虑cdq分治, 对于[l, r)递归[l, m), [m, r); 然后计算[l, m)的操作对[m, r)中询问的影响就可以了. 具体就是差分答案+排序+离散化然后树状数组维护.操作数为M的话时间 ...
- BZOJ 1176: [Balkan2007]Mokia
一道CDQ分治的模板题,然而我De了一上午Bug...... 按时间分成左右两半,按x坐标排序然后把y坐标丢到树状数组里,扫一遍遇到左边的就add,遇到右边的query 几个弱智出了bug的点, 一是 ...
- cdq分治(bzoj 1176: [Balkan2007]Mokia bzoj 2683: 简单题)
CDQ分治: 本质:对询问进行分治 优点:和莫队分块一样都属于技巧,关键时刻能免去复杂的数据结构,常数小 缺点:必须离线 参考:http://blog.csdn.net/hbhcy98/article ...
- bzoj 1176 Mokia (cdq分治)
1176: [Balkan2007]Mokia Time Limit: 30 Sec Memory Limit: 162 MB Submit: 3874 Solved: 1742 [Submit] ...
- BZOJ 1176([Balkan2007]Mokia-CDQ分治-分治询问)
1176: [Balkan2007]Mokia Time Limit: 30 Sec Memory Limit: 162 MB Submit: 185 Solved: 94 [ Submit] ...
- bzoj 4237: 稻草人(CDQ分治+单调栈+二分)
4237: 稻草人 Time Limit: 40 Sec Memory Limit: 256 MB Submit: 1352 Solved: 594 [Submit][Status][Discus ...
- Bzoj 2683: 简单题(CDQ分治)
2683: 简单题 Time Limit: 50 Sec Memory Limit: 20M. Description 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两 ...
- bzoj 3262: 陌上花开(cdq分治)
3262: 陌上花开 Time Limit: 20 Sec Memory Limit: 256 MB Submit: 2433 Solved: 1087 [Submit][Status][Disc ...
- BZOJ 2961 共点圆 CDQ分治+凸包
题目大意:给定平面,多次插入点和圆,每次插入点时询问当前插入的点是否在之前插入的所有圆中并且至少在一个圆中 直接用数据结构维护这些点和圆不是很好写,我们考虑CDQ分治 对于每层分治,我们需要对于[mi ...
最新文章
- 大数加法【HDU 1002】
- 看我如何下载韩寒博客文章笔记
- 深入理解Oracle RAC 12c 笔记
- 生态伙伴 | 小鹅通企学院入驻飞书,助力企业一键打造自己的企业大学
- MockDialog
- Java中的注解以及应用 @Deprecated @SupressWarning @Override
- jmeter(二)录制脚本
- 【Python基础入门系列】第09天:Python tuple
- python并发处理list数据_3种方式实现python多线程并发处理
- 魔兽世界客户端数据研究(四):M2文件头分析
- 多媒体查询@media
- 分享小知识:善用Group By排序
- redhat7挂载光盘
- vb.net使用DirectX入门知识
- markdown中数学符号和公式总结
- 【串口服务器rs485通信教程】存储型网关工作模式
- 断臂求生!捷信全线退出医美市场
- xgboost在LTR(学习排序)中的应用
- 微信互动营销有哪些方式?
- Win7 64位系统USB免驱设备驱动识别失败解决方法
热门文章
- 服装生产管理系统软件都有哪些实用功能?应该如何选购?
- DDMS 无法显示进程解决方案
- mysql滚动查询数据_在一个超大的表中如何实现类似滑动订单的查询
- Select2(4.0.6)城市搜索
- Python 单位(亿、万)转数字
- 【CE】技巧和注意事项(持续更新)
- [转].NET Reflector 7.0 License 机制分析
- iOS 查看.a文件的方法,可以查看有无热更新代码,防止上线被拒绝
- AI+金融:学者、产业、趋势全景报告
- dpdk 内存管理 原理剖析