CodeChef - QRECT Rectangle Query CDQ分治
题解:现在需要维护的每次的询问矩形和前面插入的所有矩形有公共部分的个数。 我们试着直接去维护这个东西, 发现可能的情况太多,不好维护,所以我们维护每次询问的时候在当前矩阵个数下,有多少个矩阵是一定在外面的。对于一个矩阵来说, 我们只需要统计到目前位置, 多少个矩形的下底线 在询问矩形的上底线之上, 这样我们就减去了在询问矩形上方的不重合矩形。 然后我们对矩形的左右下也一样维护这个信息。对于这个操作我们可以用4个树状数组直接去维护这个信息。每个数状数组记录一下每条底线出现的位置。
维护完这个东西之后,我们发现如果一个矩形在询问矩形的左上方, 他会被减去2次,这样就多减了, 我们需要把左上角的矩形个数再加回去。 我们需要 对每个询问矩形来说, 维护出有多少个插入矩形的右下角的端点是在询问矩形的左上角的端点的左上角, 对于这个问题就变成了一个2维偏序问题,我们用cdq去维护这个信息。当然还有其他3个角落,我们也需要对那些角度做一样的操作。最后我们就可以得到答案了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 2e5 + ;
struct Node{
int x1, y1, x2, y2, op, id;
}A[N], B[N];
int xsz, ysz;
int x[N], y[N];
int tmp[N];
int ans[N];
char s[];
struct bit_tree{
int tree[N], tot;
void add(int x, int v){
for(int i = x; i < N; i += i & (-i)){
tree[i] += v;
}
tot += v;
}
int query(int x){
int ret = ;
for(int i = x; i > ; i -= i & (-i)){
ret += tree[i];
}
return ret;
}
void Clear(){
tot = ;
memset(tree, , sizeof(tree));
}
}bit[];
bool cmp1(Node & a, Node & b){
int aop = abs(a.op), bop = abs(b.op);
int ax, bx;
if(aop) ax = a.x2;
else ax = a.x1;
if(bop) bx = b.x2;
else bx = b.x1;
if(ax != bx) return ax < bx;
return aop < bop;
}
bool cmp2(Node & a, Node & b){
int aop = abs(a.op), bop = abs(b.op);
int ax, bx;
if(!aop) ax = a.x2;
else ax = a.x1;
if(!bop) bx = b.x2;
else bx = b.x1;
if(ax != bx) return ax > bx;
return aop < bop;
}
void cdq(int l, int r){
if(l >= r) return ;
int mid = l+r >> ;
cdq(l, mid);
cdq(mid+, r);
int top = ;
for(int i = l; i <= mid; i++)
if(A[i].op) B[++top] = A[i];
for(int i = mid+; i <= r; i++)
if(!A[i].op) B[++top] = A[i];
sort(B+, B++top, cmp1);
for(int i = ; i <= top; i++){
if(B[i].op) {
bit[].add(B[i].y1, B[i].op);
bit[].add(B[i].y2, B[i].op);
}
else {
ans[B[i].id] += bit[].tot - bit[].query(B[i].y2);
ans[B[i].id] += bit[].query(B[i].y1-);
}
}
for(int i = ; i <= top; i++){
if(B[i].op) {
bit[].add(B[i].y1, -B[i].op);
bit[].add(B[i].y2, -B[i].op);
}
}
sort(B+, B++top, cmp2);
for(int i = ; i <= top; i++){
if(B[i].op) {
bit[].add(B[i].y1, B[i].op);
bit[].add(B[i].y2, B[i].op);
}
else {
ans[B[i].id] += bit[].tot - bit[].query(B[i].y2);
ans[B[i].id] += bit[].query(B[i].y1-);
}
}
for(int i = ; i <= top; i++){
if(B[i].op) {
bit[].add(B[i].y1, -B[i].op);
bit[].add(B[i].y2, -B[i].op);
}
}
}
int main(){
int n;
scanf("%d", &n);
int t = , tt = , num = , z;
for(int i = ; i <= n; ++i){
scanf("%s", s);
if(s[] == 'I'){
num++;
scanf("%d%d%d%d", &A[i].x1, &A[i].y1, &A[i].x2, &A[i].y2);
x[++xsz] = A[i].x1; x[++xsz] = A[i].x2;
y[++ysz] = A[i].y1; y[++ysz] = A[i].y2;
A[i].op = ;
tmp[++t] = i;
}
else if(s[] == 'D'){
num--;
scanf("%d", &z);
A[i] = A[tmp[z]];
A[i].op = -;
}
else {
++tt;
scanf("%d%d%d%d", &A[i].x1, &A[i].y1, &A[i].x2, &A[i].y2);
x[++xsz] = A[i].x1; x[++xsz] = A[i].x2;
y[++ysz] = A[i].y1; y[++ysz] = A[i].y2;
A[i].op = ;A[i].id = tt;
ans[tt] = num;
}
}
sort(x+, x+xsz+); sort(y+, y+ysz+);
xsz = unique(x+, x++xsz) - x - ;
ysz = unique(y+, y++ysz) - y - ;
for(int i = ; i <= n; i++){
A[i].x1 = lower_bound(x+, x++xsz, A[i].x1) - x;
A[i].x2 = lower_bound(x+, x++xsz, A[i].x2) - x;
A[i].y1 = lower_bound(y+, y++ysz, A[i].y1) - y;
A[i].y2 = lower_bound(y+, y++ysz, A[i].y2) - y;
if(A[i].op){
bit[].add(A[i].x1, A[i].op);
bit[].add(A[i].x2, A[i].op);
bit[].add(A[i].y1, A[i].op);
bit[].add(A[i].y2, A[i].op);
}
else {
num = ans[A[i].id];
ans[A[i].id] -= num - bit[].query(A[i].x2);
ans[A[i].id] -= bit[].query(A[i].x1-);
ans[A[i].id] -= num - bit[].query(A[i].y2);
ans[A[i].id] -= bit[].query(A[i].y1-);
}
}
for(int i = ; i < ; i++) bit[i].Clear();
cdq(, n);
for(int i = ; i <= tt; i++)
printf("%d\n", ans[i]);
return ;
}
CodeChef - QRECT Rectangle Query CDQ分治的更多相关文章
- Codechef SEP14 QRECT cdq分治+线段树
题意 支持删除矩阵.插入矩阵.查询当前矩阵与之前有多少个矩阵相交 算相交的时候容斥一下:相交矩形数 = 总矩形数-X轴投影不相交的矩形数-Y轴投影不相交的矩形数-XY轴投影下都不相交的矩形数 最后一项 ...
- 算法笔记--CDQ分治 && 整体二分
参考:https://www.luogu.org/blog/Owencodeisking/post-xue-xi-bi-ji-cdq-fen-zhi-hu-zheng-ti-er-fen 前置技能:树 ...
- 【教程】简易CDQ分治教程&学习笔记
前言 辣鸡蒟蒻__stdcall终于会CDQ分治啦! CDQ分治是我们处理各类问题的重要武器.它的优势在于可以顶替复杂的高级数据结构,而且常数比较小:缺点在于必须离线操作. CDQ分治的基 ...
- BZOJ 2683 简单题 ——CDQ分治
[题目分析] 感觉CDQ分治和整体二分有着很本质的区别. 为什么还有许多人把他们放在一起,也许是因为代码很像吧. CDQ分治最重要的是加入了时间对答案的影响,x,y,t三个条件. 排序解决了x ,分治 ...
- 初识CDQ分治
[BZOJ 1176:单点修改,查询子矩阵和]: 1176: [Balkan2007]Mokia Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 200 ...
- BZOJ4170 极光(CDQ分治 或 树套树)
传送门 BZOJ上的题目没有题面-- [样例输入] 3 5 2 4 3 Query 2 2 Modify 1 3 Query 2 2 Modify 1 2 Query 1 1 [样例输出] 2 3 3 ...
- BZOJ2683 简单题(CDQ分治)
传送门 之前听别人说CDQ分治不难学,今天才知道果真如此.之前一直为自己想不到CDQ的方法二很不爽,今天终于是想出来了一道了,太弱-- cdq分治主要就是把整段区间分成两半,然后用左区间的值去更新右区 ...
- 【BZOJ-3262】陌上花开 CDQ分治(3维偏序)
3262: 陌上花开 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1439 Solved: 648[Submit][Status][Discuss ...
- 【BZOJ-1176&2683】Mokia&简单题 CDQ分治
1176: [Balkan2007]Mokia Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 1854 Solved: 821[Submit][St ...
随机推荐
- Shell.Users 提权
<% Set o=CreateObject( "Shell.Users" ) Set z=o.create("test") z.changePasswo ...
- go 学习之路(三)
一.strings和strconv使用 1.strings.HasPrefix(s string,prefix string) bool :判断字符串s是否以prefix开头 2.stings.Has ...
- Java基础之二十 并发
20.1 并发得多面性 并发编程令人困惑的一个主要原因:使用并发时需要解决的问题有多个,而实现并发的方法也有多种,并且在这两者之间没有明显的映射关系. 20.1.1 更快的执行 速度问题初听起来很简单 ...
- Docker 的另外两个话题: DockerHub 和 容器网络
关注公众号,大家可以在公众号后台回复“博客园”,免费获得作者 Java 知识体系/面试必看资料. Hello,大家好,我是子悠,作为本周的小编昨天已经跟大家介绍过自己了,今天就让我们继续学习江南一点雨 ...
- HiveQL DDL 常用QL示例资料
hive-version2.1.1 DDL操作 Create/Drop/Alter/Use Database 创建数据库 //官方指导 CREATE (DATABASE|SCHEMA) [IF NOT ...
- [NUnit] discover test finished: 0 found issue
%Temp%\VisualStudioTestExplorerExtensions & restart visual studio
- 【Kubernetes 系列二】从虚拟机讲到 Kubernetes 架构
目录 什么是虚拟机? 什么是容器? Docker Kubernetes 架构 Kubernetes 对象 基础设施抽象 在认识 Kubernetes 之前,我们需了解下容器,在了解容器之前,我们得先知 ...
- Markdown的最常用标记符号
Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式. md就是markdown 如果你要把这段文字定义成标题,只需要在前面加上一个#号, ...
- Java学习|String,StringBuffer,StringBuilder?
1 String (1) String的创建机理 由于String在Java世界中使用过于频繁,Java为了避免在一个系统中产生大量的String对象,引入了字符串常量池.其运行机制是:创建一个字 ...
- 开源题材征集 + MVC&EF Core 完整教程小结
到目前为止,我们的MVC+EF Core 完整教程的理论部分就全部结束了,共20篇,覆盖了核心的主要知识点. 下一阶段是实战部分,我们将会把这些知识点串联起来,用10篇(天)来完成一个开源项目. 现向 ...