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 ...
随机推荐
- kvm克隆
virt-clone --original aming2 --name aming3 --file /data/kvm/aming3.qcow2 相关的克隆命令 克隆前必须关闭虚拟机 virs ...
- Python常用数据结构之collections模块
Python数据结构常用模块:collections.heapq.operator.itertools collections collections是日常工作中的重点.高频模块,常用类型由: 计数器 ...
- 发布iOS应用时,Xcode报错:Application failed codesign verification.
如下图,在发布应用时,因为codesign问题卡住了.尝试修改Target中的code sign setting,没有效果. 接着,在Developer Center删除所有证书,甚至包括Apps I ...
- numpy模块中的sum(axis)方法
1.sum函数声明 sum(a, axis=None, dtype=None, out=None, keepdims=<class 'numpy._globals._NoValue'>) ...
- 理解 Git
Git 如何保存文件 其它版本管理系统通常会保存所有文件及其历次提交的差异(diff / revision),通过 merge 原始文件与各阶段的差异就能获取任何版本的状态 而 Git 保存的是每一次 ...
- mac上搭建appium+IOS自动化测试环境(一)
阅读须知 由于OS X系统最近才开始接触,所以有些东西也不是很清楚,这里只提供方法不提供原理,能解释清楚的我也会尽量解释.可能也有一些地方说的不严谨或有错的,还望大家指点一二. 实验环境 操作系统: ...
- Appium适配Android7.0以上版本
Appium适配Android7.0以上版本 测试机型: 华为荣耀V9 安卓版本: Android7.0 appium版本: 1.65 说明: 公司新采购了一批安卓机器,拿了其中一台华为荣耀V9跑之前 ...
- H3C无线路由器安装与设置
一.电脑与路由器的连接利用一根cat5e网线一头连接到电脑上笔记本或台式机都可以,另一头连接到无线路由器的LAN口任意LAN口都可以二.设置无线路由器完成路由器安装与电脑连接后,接下首次使用就需要设置 ...
- AVS、MPEG-2、H264标准文档
联合信源对AVS解码源码和相应的AVS码流.AVS码流太大,可以从http://cosoft.org.cn/projects/avsdec下载.解压avsdec_source.zip后,用VC6编译a ...
- Android 插件化方案(动态加载)总结
1.作用 大多数Android开发人员开始接触这个问题是因为 App 爆棚了,方法数超过了一个 Dex 最大方法数 65535 的上限,因而便有了插件化的概念,将一个 App 划分为多个插件(Apk ...