gym101964G Matrix Queries seerc2018k题 cdq分治
题目大意:
二维平面上有q次操作,每次操作可以是添加一个点,也可以是添加一个矩形,问每次操作后,有多少 点-矩形 这样的pair,pair的条件是点被矩形覆盖(边缘覆盖也算)。
思路:
cdq分治,由于加点和加矩形都既是修改操作又是查询操作,而且两种方式完全不一样,所以用两部分cdq来写。
先将矩形拆成四个点,并且向左下角扩展一个单元,左下角和右上角的点的权值赋为1,左上角和右下角赋为-1。
对于加矩形的操作,遇到加的点则修改树状数组,遇到矩形的点查询小于这个矩形的值,并且乘以这个矩形点的权值。
对于加点的操作,由于往左下角扩展了,所以应该按x从右往左处理,碰到一个矩形点,更新树状数组,碰到加的点,则ans+=sum(m)-sum(y-1),m是y的上界,因为sum(m)是刚好抵消的情况(等于0),而sum(y-1)则代表了有几个矩形的右下角在这个点的下方。
(还是看代码比较好写,注意树状数组的上界,sum(m)不要作死的用sum(m+1)代替,因为这个自闭了)。
#include<bits/stdc++.h>
using namespace std;
const int maxn=;
int q,tot,m,brr[maxn<<],maxd;
long long ans[maxn],res[maxn<<];
struct node{
int id,x,y,type,val;
}a[maxn<<],b[maxn<<];
inline void Hash(){
sort(brr+,brr++m);
m=unique(brr+,brr++m)-brr-;
for(int i=;i<=tot;i++)
{
a[i].x=lower_bound(brr+,brr++m,a[i].x)-brr;
a[i].y=lower_bound(brr+,brr++m,a[i].y)-brr;
maxd=max(maxd,a[i].y);
}
}
inline void add(int x,int v){
while(x<=m){res[x]+=v, x+= x & (-x);}
}
inline long long sum(int x){
long long tu=;
while(x>){tu+=res[x], x -= x & (-x);}
return tu;
}
inline bool cmpx(const node &a,const node &b){
if(a.x!=b.x)return a.x<b.x;
return a.id<b.id;
}
inline bool cmpx2(const node &a,const node &b){
if(a.x!=b.x)return a.x>b.x;
return a.id<b.id;
} inline void cdq1(int l,int r){//加点
if(l==r)return ; int mid=l+((r-l)>>);
// printf("l:%d r:%d mid:%d\n",l,r,mid);
cdq1(l,mid),cdq1(mid+,r);
int cc=;
for(int i=l;i<=mid;i++)
{
b[++cc]=a[i];
b[cc].id=;
}
for(int i=mid+;i<=r;i++)
{
b[++cc]=a[i];
}
sort(b+,b++cc,cmpx2);
for(int i=;i<=cc;i++)
{
if(b[i].id==){
if(b[i].type==)continue;
add(b[i].y,b[i].val);
// printf("y:%d val:%d\n",b[i].y,b[i].val);
}else{
if(b[i].type==)continue;
ans[b[i].id]+=sum(m)-sum(b[i].y-);//**sum(m+1)
}
}
for(int i=;i<=cc;i++)
{
if(b[i].id==&&b[i].type==)add(b[i].y,-b[i].val);
}
} inline void cdq2(int l,int r){//加矩形
if(l==r)return ;
int mid=l+((r-l)>>);
cdq2(l,mid),cdq2(mid+,r);
int cc=;
for(int i=l;i<=mid;i++)
{
b[++cc]=a[i];
b[cc].id=;
}
for(int i=mid+;i<=r;i++)
{
b[++cc]=a[i];
}
sort(b+,b++cc,cmpx);
for(int i=;i<=cc;i++)
{
if(b[i].id==){
if(b[i].type==)continue;
add(b[i].y,);
}else{
if(b[i].type==)continue;
ans[b[i].id]+=sum(b[i].y)*b[i].val;
}
}
for(int i=;i<=cc;i++)
{
if(b[i].id==&&b[i].type==)add(b[i].y,-);
}
} int main(){
scanf("%d",&q);
tot=;
for(int i=;i<=q;i++)
{
int type,x1,y1,x2,y2;
scanf("%d",&type);
a[++tot].type=type;
a[tot].id=i;
if(a[tot].type==)
{
scanf("%d%d",&x1,&y1);
a[tot].x=x1,a[tot].y=y1;
brr[++m]=x1,brr[++m]=y1;
}
else
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
x1--,y1--;//tuo zhan ju xin
brr[++m]=x1,brr[++m]=x2,brr[++m]=y1,brr[++m]=y2;
a[tot].x=x1,a[tot].y=y1,a[tot].val=;
a[++tot].x=x1,a[tot].y=y2,a[tot].val=-,a[tot].type=type,a[tot].id=i;
a[++tot].x=x2,a[tot].y=y2,a[tot].val=,a[tot].type=type,a[tot].id=i;
a[++tot].x=x2,a[tot].y=y1,a[tot].val=-,a[tot].type=type,a[tot].id=i;
}
}
Hash(); cdq2(,tot);
cdq1(,tot); for(int i=;i<=q;i++)
{
ans[i]=ans[i]+ans[i-];
printf("%lld\n",ans[i]);
} }
gym101964G Matrix Queries seerc2018k题 cdq分治的更多相关文章
- gym101964G Matrix Queries seerc2018g题 数学归纳法+线段树(递归)
题目传送门 题目大意: 给出2^k大小的白色矩形,q次操作,每次将一行或者一列颜色反转,问总体矩阵的价值,矩阵的价值定义是,如果整个矩阵颜色相同,价值为1,否则就把这个矩阵切成四份,价值为四个小矩阵的 ...
- 【BZOJ-1176&2683】Mokia&简单题 CDQ分治
1176: [Balkan2007]Mokia Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 1854 Solved: 821[Submit][St ...
- BZOJ 2683: 简单题 [CDQ分治]
同上题 那你为什么又发一个? 因为我用另一种写法又写了一遍... 不用排序,$CDQ$分治的时候归并排序 快了1000ms... #include <iostream> #include ...
- bzoj2683简单题 cdq分治
2683: 简单题 Time Limit: 50 Sec Memory Limit: 128 MBSubmit: 1803 Solved: 731[Submit][Status][Discuss] ...
- bzoj 1176: [Balkan2007]Mokia&&2683: 简单题 -- cdq分治
2683: 简单题 Time Limit: 50 Sec Memory Limit: 128 MB Description 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要 ...
- 【BZOJ1176】[Balkan2007]Mokia/【BZOJ2683】简单题 cdq分治
[BZOJ1176][Balkan2007]Mokia Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=1600 ...
- 【bzoj1176】[Balkan2007]Mokia/【bzoj2683】简单题 CDQ分治+树状数组
bzoj1176 题目描述 维护一个W*W的矩阵,初始值均为S(题目描述有误,这里的S没有任何作用!).每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数 ...
- BZOJ2683: 简单题(cdq分治 树状数组)
Time Limit: 50 Sec Memory Limit: 128 MBSubmit: 2142 Solved: 874[Submit][Status][Discuss] Descripti ...
- BZOJ 2683 简单题 cdq分治+树状数组
题意:链接 **方法:**cdq分治+树状数组 解析: 首先对于这道题,看了范围之后.二维的数据结构是显然不能过的.于是我们可能会考虑把一维排序之后还有一位上数据结构什么的,然而cdq分治却可以非常好 ...
随机推荐
- springboot @Value 类中读取配置文件 .properties null 原因和解决方案
问题:在一个工具类中,通过@Value来映射配置文件的值,得到的总是null 原因:不能用new工具类的方式,应该是用容器注册(@Autowried)的方式使用此工具类,就能得到配置文件里的值 上代码 ...
- solr第一天 基础增删改查操作
全文检索技术 Lucene&Solr Part2 1 课程计划 1.索引库的维护 a) 添加文档 b) 删除文档 c) 修改文档 2.Lucene的查询 a) ...
- 浅析junit4及扩展实践
junit框架相关源代码分析,网上已经有很多了,本篇不做过多相关解说,主要还是要自己多读相关源代码.本篇主要对自动化测试过程相关的测试用例,测试数据,测试结果结合junit做相关扩展说明. 如果要解读 ...
- shell chmod中数字与字母的含义
数字与字母的组合是chmod命令赋予文件,目录访问权限的方式 访问权限:可读,可写,可执行 字母表示:r , w , x 数字表示:4 , 2 , 1 , ...
- c语言实践 打印三角形
效果如下: 我是怎么考虑这个问题的. 首先共有5行,那么我们需要一个循环,让这个循环走5遍. 那么我们有个大概的代码结构 for(int i=0;i<5;i++) { } i的定义域是[0,4] ...
- 35.MID() 函数
MID() 函数 MID() 函数 MID 函数用于从文本字段中提取字符. SQL MID() 语法 SELECT MID(column_name,start[,length]) FROM table ...
- Part6-点亮指路灯_lesson1
1. 2.GPIO 查阅芯片手册:GPIO 代码: 3.外设基地址初始化 打开arm核手册, 基地址为0x70000000,去搜芯片手册6410, 把这个基地址告诉处理器,通过协处理器的cp15, 转 ...
- Part5核心初始化_lesson4---关闭mmu
1.ARM存储体系 2.cache 3.虚拟地址 那么谁来完成把虚拟地址转换成物理地址呢? 4.这个工作就由MMU来转换!! 5.关闭MMU和cache 他们都是通过cp15协处理器来控制的!应该在A ...
- Requests接口测试(一)
接口测试概念 接口测试是测试系统组件间接口的一种测试.接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点.测试的重点是要检查数据的交换,传递和控制管理过程,以及系统间的相互逻辑依赖关 ...
- jquery数组拼接
var a=[]; var c=[80,90,70,100] var b={'张三':19,'成绩':c}; a.push(b); console.log("测试案例",a); 同 ...