CDQ 分治算法模板
CDQ分治
1.三维偏序问题:三维偏序(陌上花开)
#include<bits/stdc++.h>
#define RG register
#define IL inline
#define _ 200005
using namespace std;
IL int gi(){
RG int data = 0 , m = 1; RG char ch = 0;
while(ch != '-' && (ch<'0'||ch>'9'))ch = getchar();
if(ch == '-'){m = -1; ch = getchar();}
while('0'<=ch && ch<='9')
data = (data<<3) + (data<<1) + (ch - '0') , ch = getchar();
return (m) ? data : -data;
}
int tot,bt[_],n,k,f[_],g[_],blg[_]; long long ans[_];
struct Node{
int a, b, c , w , id;
//w记录这个节点对应多少个真实节点,id则是其对应编号.
bool operator <(const Node &B)const{
return (b == B.b) ? c <= B.c : b < B.b;}
};
Node q1[_],q[_],tmp[_];
namespace BIT{
IL void Update(RG int ps,RG int dt){
for(RG int i = ps; i <= k; i += (i&-i))bt[i] += dt;
}
IL void Clear(RG int ps){
for(RG int i = ps; i <= k; i += (i&-i))bt[i] = 0;
}
IL int Query(RG int ps){
RG int res = 0;
for(RG int i = ps; i > 0; i -= (i&-i))res += bt[i];
return res;
}
}
void cdq(RG int L,RG int R){
if(L == R)return;
RG int mid = (L+R)>>1; cdq(L,mid); cdq(mid+1,R);
RG int l = L , r = mid+1 , oo = L-1;
while(l <= mid && r <= R){
if(q[l] < q[r])
BIT::Update(q[l].c,q[l].w) ,
tmp[++oo] = q[l++];
else
g[q[r].id] += BIT::Query(q[r].c) ,
tmp[++oo] = q[r++];
}
while(l <= mid)tmp[++oo] = q[l++];
while(r <= R)
g[q[r].id] += BIT::Query(q[r].c) ,
tmp[++oo] = q[r++];
for(RG int i = L; i <= R; i ++)
BIT::Clear(tmp[i].c) , q[i] = tmp[i];
return;
}
IL bool cmp(Node a,Node b){
if(a.a != b.a)return a.a < b.a;
if(a.b != b.b)return a.b < b.b;
if(a.c != b.c)return a.c < b.c;
return a.id < b.id; //注意:这里一定要随便定义一个优先级
}
IL bool Equl(int nw,int cp){
if(!cp)return false;
else return (q1[nw].a==q[cp].a &&
q1[nw].b==q[cp].b && q1[nw].c==q[cp].c);
}
int main(){
n = gi(); k = gi();
for(RG int i = 1,a,b,c; i <= n; i ++)
a = gi(),b = gi(),c = gi(),
q1[i] = (Node){a , b , c , 1 , i};
//去重:
tot = 0;
sort(q1+1,q1+n+1,cmp);
for(RG int i = 1; i <= n; i ++){
if(!Equl(i,tot))
q[++tot] = q1[i] , q[tot].w = 1 , q[tot].id = tot;
else q[tot].w ++;
blg[i] = tot; //记录i点是对应去重后的哪个节点
}
cdq(1,tot);
// f[i] 表示去重前点i满足 (aj<=ai,bj<=bi,cj<=ci) 的j的个数.
// g[i] 表示去重后点i满足条件的j的个数
for(RG int i = 1; i <= tot; i ++)g[q[i].id] += q[i].w-1;
for(RG int i = 1; i <= n; i ++)f[i] = g[blg[i]];
for(RG int i = 1; i <= n; i ++)ans[f[i]] ++;
for(RG int i = 0; i < n; i ++)printf("%lld\n",ans[i]);
return 0;
}
2.动态逆序对问题:[CQOI2011]动态逆序对
#include<bits/stdc++.h>
#define RG register
#define IL inline
#define _ 300005
using namespace std;
IL int gi(){
RG int data = 0 , m = 1; RG char ch = 0;
while(ch != '-' && (ch<'0'||ch>'9'))ch = getchar();
if(ch == '-'){m = -1; ch = getchar();}
while('0'<=ch && ch<='9')
data = (data<<3) + (data<<1) + (ch - '0') , ch = getchar();
return (m) ? data : -data;
}
struct Query{
int tm , ps , val;
bool operator < (const Query &B)const{ return ps < B.ps; }
};
Query q[_] , tmp[_];
int ans[_],bt[_],n,m,pos[_]; long long Ans; bool vis[_];
namespace BIT{
IL void Update(RG int ps,RG int dt){
for(RG int i = ps; i <= n; i += (i&-i))bt[i] += dt;
}
IL int Query(RG int ps){
RG int res = 0;
for(RG int i = ps; i > 0; i -= (i&-i))res += bt[i];
return res;
}
}
void cdq(RG int L,RG int R){
if(L == R)return;
RG int mid = (L+R)>>1; cdq(L,mid); cdq(mid+1,R);
RG int l = L , r = mid+1 , oo = L-1;
while(l<=mid && r<=R)
if(q[l] < q[r])tmp[++oo] = q[l++]; else tmp[++oo] = q[r++];
while(l<=mid)tmp[++oo] = q[l++];
while(r<=R)tmp[++oo] = q[r++];
for(RG int i = L; i <= R; i ++)q[i] = tmp[i];
//get - behind - smaller
for(RG int i = L; i <= R; i ++)
if(q[i].tm <= mid)BIT::Update(q[i].val,1);
else ans[q[i].tm] += BIT::Query(n) - BIT::Query(q[i].val);
for(RG int i = L; i <= R; i ++)
if(q[i].tm <= mid)BIT::Update(q[i].val,-1);
//get - front - bigger
for(RG int i = R; i >= L; i --)
if(q[i].tm <= mid)BIT::Update(q[i].val,1);
else ans[q[i].tm] += BIT::Query(q[i].val);
for(RG int i = R; i >= L; i --)
if(q[i].tm <= mid)BIT::Update(q[i].val,-1);
return;
}
IL bool cmp(Query a,Query b){return a.tm<b.tm;}
int main(){
n = gi(); m = gi();
RG int tot = 0;
for(RG int u,i = 1; i <= n; i ++)
u = gi() , pos[u] = i , vis[u] = 1;
for(RG int u,i = n; i >= n-m+1; i --)
u = gi() , vis[u] = 0 ,
q[++tot] = (Query){i,pos[u],u};
RG int cnt = n - m + 1;
for(RG int i = 1; i <= n; i ++)
if(vis[i])q[++tot] = (Query){--cnt,pos[i],i};
sort(q+1,q+tot+1,cmp);
cdq(1,tot);
Ans = 0;
for(RG int i = 1; i <= n; i ++)Ans += ans[i];
for(RG int i = n; i >= n-m+1; i --)
printf("%lld\n",Ans) , Ans -= ans[i];
return 0;
}
离线修改与查询问题:树状数组 1
#include<bits/stdc++.h>
#define RG register
#define IL inline
#define ll long long
#define _ 4*500005
using namespace std;
int n,m,ask,tot; ll ans[_];
struct Do{
int typ,pos,val;
bool operator <(const Do &B)const{
return (pos == B.pos)?typ < B.typ : pos < B.pos; }
};
Do q[_],tmp[_];
void cdq(RG int L,RG int R){
if(L == R)return;
RG int mid = (L+R)>>1; cdq(L,mid); cdq(mid+1,R);
RG ll upt = 0 , l = L , r = mid+1 , oo = 0;
while(l <= mid && r <= R){
if(q[l] < q[r]){
if(q[l].typ == 1)upt += q[l].val;
tmp[++oo] = q[l++];
}
else {
if(q[r].typ == 2)ans[q[r].val] -= upt;
if(q[r].typ == 3)ans[q[r].val] += upt;
tmp[++oo] = q[r++];
}
}
while(l <= mid){
if(q[l].typ == 1)upt += q[l].val;
tmp[++oo] = q[l++];
}
while(r <= R){
if(q[r].typ == 2)ans[q[r].val] -= upt;
if(q[r].typ == 3)ans[q[r].val] += upt;
tmp[++oo] = q[r++];
}
for(RG int i = L; i <= R; i ++)q[i] = tmp[i-L+1];
}
int main(){
scanf("%d %d",&n,&m);
for(RG int i = 1,ww; i <= n; i ++)
scanf("%d",&ww), q[++tot] = (Do){1,i,ww};
ask = 0;
for(RG int i = 1,tp,ps,ww; i <= m; i ++){
scanf("%d %d %d",&tp,&ps,&ww);
if(tp == 1)q[++tot] = (Do){1,ps,ww};
else
q[++tot] = (Do){2,ps-1,++ask} ,
q[++tot] = (Do){3,ww,ask};
}
cdq(1,tot);
for(RG int i = 1; i <= ask; i ++)cout<<ans[i]<<endl;
return 0;
}
CDQ 分治算法模板的更多相关文章
- CDQ分治嵌套模板:多维偏序问题
CDQ分治2 CDQ套CDQ:四维偏序问题 题目来源:COGS 2479 偏序 #define LEFT 0 #define RIGHT 1 struct Node{int a,b,c,d,bg;}; ...
- P3810 【模板】三维偏序(陌上花开)cdq分治
传送门:https://www.luogu.org/problemnew/show/P3810 cdq分治的模板题,第一层外部排序,第二层cdq归并排序,这个时候不用考虑第一次的顺序,第三次用树状数组 ...
- CDQ分治学习笔记
数据结构中的一块内容:$CDQ$分治算法. $CDQ$显然是一个人的名字,陈丹琪(NOI2008金牌女选手) 这种离线分治算法被算法界称为"cdq分治" 我们知道,一个动态的问题一 ...
- 『cdq分治和多维偏序问题』
更新了三维偏序问题的拓展 cdq分治 \(cdq\)分治是一种由\(IOI\ Au\)选手\(cdq\)提出的离线分治算法,又称基于时间的分治算法. 二维偏序问题 这是\(cdq\)分治最早提出的时候 ...
- 初学CDQ分治-NEU1702
关于CDQ分治,首先需要明白分治的复杂度. T(n) = 2T(n/2)+O(kn), T(n) = O(knlogn) T(n) = 2T(n/2)+O(knlogn), T(n) = O(knlo ...
- CDQ分治入门 + 例题 Arnooks's Defensive Line [Uva live 5871]
CDQ分治入门 简介 CDQ分治是一种特别的分治方法,它由CDQ(陈丹琦)神犇于09国家集训队作业中首次提出,因此得名.CDQ分治属于分治的一种.它一般只能处理非强制在线的问题,除此之外这个算法作为某 ...
- 【BZOJ4237】 稻草人 CDQ分治+单调栈
## 题目描述 JOI村有一片荒地,上面竖着N个稻草人,村民们每年多次在稻草人们的周围举行祭典. 有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地.和启示中的一样,田地需要满足以下 ...
- 模板:CDQ分治
UPD:18.06.15修正一些错误,感谢评论区巨佬orz CDQ分治不是一个顾名思义的东西,CDQ分治是为了纪念神犇陈丹琦而命名的一种算法. 那么CDQ分治能干什么?CDQ分治主要是用来解决一类”操 ...
- 【算法学习】【洛谷】cdq分治 & P3810 三维偏序
cdq是何许人也?请参看这篇:https://wenku.baidu.com/view/3b913556fd0a79563d1e7245.html. 在这篇论文中,cdq提出了对修改/询问型问题(Mo ...
随机推荐
- python重新利用shodan API
前言: 之前写过一个shodan的API调用 感觉写的不这么好.然后现在重新写一个 shodan介绍: shodan是互联网上最可怕的搜索引擎. CNNMoney的一篇文章写道,虽然目前人们都认为谷歌 ...
- SSE图像算法优化系列十七:一些图像处理中常用小过程的SSE实现。
在做图像处理的SSE优化时,也会经常遇到一些小的过程.数值优化等代码,本文分享一些个人收藏或实现的代码片段给大家. 一.快速求对数运算 对数运算在图像处理中也是个经常会遇到的过程,特备是在一些数据压缩 ...
- linux磁盘及分区详解
1.Linux 分区简介 1.1 主分区 vs 扩展分区 硬盘分区表中最多能存储四个分区,但我们实际使用时一般只分为两个分区,一个是主分区(Primary Partion)一个是扩展分区(extend ...
- ch11 持有对象
Java集合的基本类型:List.Set.Queue.Map 使用容器时若未指定泛型参数ArrayList apples=new ArrayList();,则容器中所有元素都为Object类型,使用时 ...
- linux shell 和linux 命令的区别?windows shell 和 windows 命令呢?
shell翻译成壳的意思,它是包裹在linux内核外层的,一个可通过一系列的linux命令对操作系统发出相关指令的人机界面. shell可以通过其条件语句和循环语句等,把一系列linux命令结合在一起 ...
- 剑指offer面试题-Java版-持续更新
最近在用Java刷剑指offer(第二版)的面试题.书中原题的代码采用C++编写,有些题的初衷是为了考察C++的指针.模板等特性,这些题使用Java编写有些不合适.但多数题还是考察通用的算法.数据结构 ...
- 轻松掌握VS Code开发.Net Core及创建Xunit单元测试
前言 本篇文章主要还是介绍使用 VS Code 进行.Net Core开发和常用 CLI命令的使用,至于为啥要用VS Code ,因为它是真的是好看又好用 :) ,哈哈,主要还是为了跨平台开发做准备. ...
- Ubuntu17.10下启动Rancher
1.安装Docker: 获取最新的docker安装包 wget -qO- https://get.docker.com/ | sh 2.启动docker后台服务: service docker sta ...
- 【spring-boot】spring aop 面向切面编程初接触
众所周知,spring最核心的两个功能是aop和ioc,即面向切面,控制反转.这里我们探讨一下如何使用spring aop. 1.何为aop aop全称Aspect Oriented Programm ...
- python技巧
python小技巧: 1.强烈建议使用Python的r前缀,就不用考虑转义的问题了. 2.正则表达式的使用: test = '用户输入的字符串' if re.match(r'正则表达式', test) ...