题目传送门

题目大意:

  二维平面上有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分治的更多相关文章

  1. gym101964G Matrix Queries seerc2018g题 数学归纳法+线段树(递归)

    题目传送门 题目大意: 给出2^k大小的白色矩形,q次操作,每次将一行或者一列颜色反转,问总体矩阵的价值,矩阵的价值定义是,如果整个矩阵颜色相同,价值为1,否则就把这个矩阵切成四份,价值为四个小矩阵的 ...

  2. 【BZOJ-1176&2683】Mokia&简单题 CDQ分治

    1176: [Balkan2007]Mokia Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 1854  Solved: 821[Submit][St ...

  3. BZOJ 2683: 简单题 [CDQ分治]

    同上题 那你为什么又发一个? 因为我用另一种写法又写了一遍... 不用排序,$CDQ$分治的时候归并排序 快了1000ms... #include <iostream> #include ...

  4. bzoj2683简单题 cdq分治

    2683: 简单题 Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 1803  Solved: 731[Submit][Status][Discuss] ...

  5. bzoj 1176: [Balkan2007]Mokia&&2683: 简单题 -- cdq分治

    2683: 简单题 Time Limit: 50 Sec  Memory Limit: 128 MB Description 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要 ...

  6. 【BZOJ1176】[Balkan2007]Mokia/【BZOJ2683】简单题 cdq分治

    [BZOJ1176][Balkan2007]Mokia Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=1600 ...

  7. 【bzoj1176】[Balkan2007]Mokia/【bzoj2683】简单题 CDQ分治+树状数组

    bzoj1176 题目描述 维护一个W*W的矩阵,初始值均为S(题目描述有误,这里的S没有任何作用!).每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数 ...

  8. BZOJ2683: 简单题(cdq分治 树状数组)

    Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 2142  Solved: 874[Submit][Status][Discuss] Descripti ...

  9. BZOJ 2683 简单题 cdq分治+树状数组

    题意:链接 **方法:**cdq分治+树状数组 解析: 首先对于这道题,看了范围之后.二维的数据结构是显然不能过的.于是我们可能会考虑把一维排序之后还有一位上数据结构什么的,然而cdq分治却可以非常好 ...

随机推荐

  1. Linux xclip命令

    一.简介 xclip命令建立了终端和剪切板之间通道,可以用于以命令的方式将终端输出或文件的内容保存到剪切板中,也可以用于将剪切板的内容输出到终端或文件中. 在 X 系统里面,从一个窗口复制一段文字到另 ...

  2. javac老提示无效的标记

    加上-cp libs/*后,就开始提示无效的标记,搞了半天,似乎是shell展开的问题,估计是把后面的jar文件当源文件了? 加上引号就行了-cp "libs/*",不让shell ...

  3. Apache rotatelogs命令

    一.简介 rotatelogs 是 Apache 自带的管道日志程序,可以完美的实现日志的轮转功能. 二.语法 Usage: rotatelogs [-v] [-l] [-L linkname] [- ...

  4. Django框架 之 ORM中介模型

    Django框架 之 ORM中介模型 中介模型 处理类似搭配 pizza 和 topping 这样简单的多对多关系时,使用标准的ManyToManyField  就可以了.但是,有时你可能需要关联数据 ...

  5. jqgrid 编辑表格(包含下拉框)

    .1在jqgrid 按钮 <asp:JQGridColumn TextAlign=" DataField="act" Visible="True" ...

  6. 复习action委托

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  7. 转:Linux awk 命令 说明

    一.  AWK 说明 awk是一种编程语言,用于在linux/unix下对文本和数据进行处理.数据可以来自标准输入.一个或多个文件,或其它命令的输出.它支持用户自定义函数和动态正则表达式等先进功能,是 ...

  8. session的应用----验证码

    昨天登录功能中叙述了密码 用户名的数据库验证以及转发 那么这篇文章在昨天的基础上 处理验证码的验证功能,今天需要用到session域,session用于一次会话. package cn.lijun.d ...

  9. GlobalAlloc()和malloc()、HeapAlloc()

    两者都是在堆上分配内存区.  malloc()是C运行库中的动态内存分配函数,WINDOWS程序基本不使用了,因为它比WINDOWS内存分配函数少了一些特性,如,整理内存.  GlobalAlloc( ...

  10. 【大数据之数据仓库】HAWQ versus GreenPlum

    谈到GreenPlum,肯定会有同事说HAWQ!是的,在本系列第一篇选型流水记里,也有提到.因为对HAWQ接触有限,没有深入具体了解,所以很多信息都是来自于博文,人云亦云,我把看过的资料简要整理,希望 ...