对CDQ深一步的理解

昨天做了一道CDQ,看了一堆CDQ可做的题,今天又做了一道四维偏序

感觉对CDQ的理解又深了一点,故来写一写现在自己对于CDQ的理解

CDQ其实就是实现了这样的一个问题的转化:

\(a_{l} < a_{l+1} < ... < a_r => (a_l,a_{l+1},...,a_{mid}) \text{都小于} (a_{mid+1},a{mid+2},...,a_r)\)

然后我们就知道这时候左边所有的点都一定小于右边的点

在四维偏序的算法中,那就是左边的点可以对右边的点做出贡献(仅在当前维度下)

这样就强行消除了一个维度的限制.

四维偏序

COGS 2479

题目大意

给定一个有\(n\)个元素的序列,元素编号为\(1~n\),每个元素有三个属性\(a,b,c\),求序列中满足\(i<j\)且\(a_i<a_j\)且\(b_i<b_j\)且\(c_i<c_j\)的数对\((i,j)\)的个数。

题解

我们把下标也看作一个维度,那么这就是个四维偏序

我们在下标的维度上CDQ

然后记录每个元素在第一次CDQ中是较小的还是较大的.

因为只有较小的元素才能对较大的元素做出贡献

只有较大的元素才能接受较小的元素的影响.

所以我们处理出来后这就变成了一个三维偏序

所以我们在对这个序列(CDQ+扫描线+树状数组)求三维偏序即可

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 50010;
struct Node{
int a,b,c;
bool is_sm;
Node(){a=b=c=is_sm = 0;}
}a[maxn],tmp1[maxn],tmp2[maxn];
int c[maxn],n,init_tmp[maxn],ans=0;
#define lowbit(x) (x&-x)
inline void modify(int x,int y){
for(;x<=n;x+=lowbit(x)) c[x] += y;
}
inline int query(int x){
int ret = 0;
for(;x;x-=lowbit(x)) ret += c[x];
return ret;
}
void solve2(int l,int r){
if(l == r) return ;
int mid = l+r >> 1;
solve2(l,mid);solve2(mid+1,r);
int i = l,j = mid+1,k = l;
Node *a = tmp1,*tmp = tmp2;
init_tmp[0] = 0;
while(i <= mid || j <= r){
if((j > r) || (i <= mid && a[i].b < a[j].b)){
if( a[i].is_sm){
modify(a[i].c,1);
init_tmp[++init_tmp[0]] = i;
}tmp[k++] = a[i++];
}else{
if(!a[j].is_sm){
ans += query(a[j].c);
}tmp[k++] = a[j++];
}
}for(int i = 1;i<=init_tmp[0];++i) modify(a[init_tmp[i]].c,-1);
copy(tmp+l,tmp+r+1,a+l);
}
void solve1(int l,int r){
if(l == r) return ;
int mid = l+r >> 1;
solve1(l,mid);solve1(mid+1,r);
int i = l,j = mid+1,k = l;
Node *tmp = tmp1;
while(i <= mid || j <= r){
if((j > r) || (i <= mid && a[i].a < a[j].a)){
(tmp[k++] = a[i++]).is_sm = true;
}else (tmp[k++] = a[j++]).is_sm = false;
}
copy(tmp+l,tmp+r+1,a+l);
solve2(l,r);
}
int main(){
// freopen("partial_order.in","r",stdin);
// freopen("partial_order.out","w",stdout);
read(n);
for(int i=1;i<=n;++i) read(a[i].a);
for(int i=1;i<=n;++i) read(a[i].b);
for(int i=1;i<=n;++i) read(a[i].c);
solve1(1,n);printf("%d\n",ans);
getchar();getchar();
return 0;
}

最新文章

  1. fir.im Weekly - 除了新 MacBook Pro,近期值得关注的移动开发好资源
  2. Maven构件解析(转)
  3. [原创]南水之源A*(A-Star)算法
  4. Response返回JSON数据到前台页面
  5. hdu2602
  6. [改善Java代码]不要只替换一个类
  7. 3 委托、匿名函数、lambda表达式
  8. 【转】GitHub 优秀的 Android 开源项目
  9. AndroidStudio项目.gitignore文件内容
  10. stm32之USART学习
  11. 域名系统DNS
  12. 第一安装oracle数据库后,需要创建一个用户,给用户解锁并赋予权限
  13. 解决`向github提交代码是老要输入用户名密码`
  14. 常用UI框架
  15. cglib根据数据动态生成对象
  16. vue 路由元信息
  17. tomcat通过一个端口号实现多域名访问
  18. 04Hadoop中的setPartitionerClass/SortComparator/GroupingComparator问题
  19. KBMMW 4.81.00 发布
  20. NoSQL入门第一天——NoSQL入门与基本概述

热门文章

  1. phpstorm 设置
  2. 怎么样自己动手写OS
  3. Android Calendar的学习与运用
  4. python 基础 1.4 python运算符
  5. EasyNVR H5无插件摄像机直播解决方案前端解析之:videojs初始化的一些样式处理
  6. IIS发布问题集锦
  7. virtual dynamic shared object
  8. php验证身份证号码有效性
  9. 前端几个笔试题及答案(bd)
  10. PHP通过session id 实现session共享和登录验证的代码