CDQ分治学习
Posted uid001
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CDQ分治学习相关的知识,希望对你有一定的参考价值。
例1. 给定序列, 2种操作, (1)单点加 (2)区间求和
询问看成二维键值对$(t,x)$, $t$为操作时间, $x$为操作位置, 区间求和转化为两个前缀求和做差, 那么问题就等价于求所有$ttle t$, $xxle x$的权值和, 也就是一个二维偏序问题, 时间已经默认有序, 直接对操作位置归并排序一次即可求出. 要注意操作位置相同时, 询问操作要排在前面.
#include <iostream> #include <algorithm> #include <cstdio> #define REP(i,a,n) for(int i=a;i<=n;++i) #define PER(i,a,n) for(int i=n;i>=a;--i) using namespace std; const int N = 3e6+10; int n, m, tot, totx; struct _ { int type,id,v; bool operator < (const _ &rhs) const { return id<rhs.id||id==rhs.id&&type<rhs.type; } } q[N], tmp[N]; int ans[N]; void merge(int l, int r) { if (l==r) return; int mid = l+r>>1; merge(l,mid),merge(mid+1,r); int p1=l, p2=mid+1, s=0; REP(i,l,r) { if (p2>r||(p1<=mid&&q[p1]<q[p2])) { if (q[p1].type==0) s+=q[p1].v; tmp[i]=q[p1++]; } else { if (q[p2].type==2) ans[q[p2].v]+=s; else if (q[p2].type==1) ans[q[p2].v]-=s; tmp[i]=q[p2++]; } } REP(i,l,r) q[i]=tmp[i]; } int main() { scanf("%d%d", &n, &m); REP(i,1,n) { ++tot; scanf("%d", &q[tot].v); q[tot].id = i; } REP(i,1,m) { int op, l, r, x, v; scanf("%d", &op); if (op==1) { scanf("%d%d", &x, &v); q[++tot]={0,x,v}; } else { ++totx,scanf("%d%d", &l, &r); q[++tot]={1,l-1,totx}; q[++tot]={2,r,totx}; } } merge(1,tot); REP(i,1,totx) printf("%d ", ans[i]); }
例2. 给定n个三元组, 对于每个三元组(x,y,z), 求有多少三元组$(x_0,y_0,z_0)$, 满足$x<x_0,y<y_0,z<z_0$
以上是关于CDQ分治学习的主要内容,如果未能解决你的问题,请参考以下文章