首页 > 其他分享 >cdq分治

cdq分治

时间:2023-07-21 18:44:55浏览次数:39  
标签:return int Max 分治 mid kk cdq

cdq分治是用分治来解决偏序(多是三维偏序)问题 其实我也不知道具体解决什么

这里就先以P3870陌上花开【三维偏序】为例

要求的就是\(\sum_{i=0}^{n}\) 中 \(a_i<a_j\)且\(b_i<b_j\)且\(c_i<c_j\)且\(i\not=j\)的个数

这里就是典型的三维偏序

那思路肯定都是先找\(a_i<a_j\),再找\(b_i<b_j\),最后找\(c_i<c_j\),cdq也是这样想的

  • 芝士思路

先将整个序列以\(a_i\)的值从大到小排序,这样我们就可以基本解决 \(a\) 数组的问题了
那 \(b\) 数组呢?我们考虑将排好序的 \(a\) 数组进行二分,那么我们是可以保证每次二分之后 \(l-mid\) 里的 \(a\) 是肯定小于 \((mid+1)-r\) 的,那么这时我们就可以放心的求 \(b\) 数组了。
我们求 \(b\) 的方法就是搞两个指针,分别从\(l\)和\((mid+1)\)开始往后跑,来比较他们的 \(b\) ,这时就可以找到对于每个 \(j\) 小于等于它 \(b\) 的 \(i\) 了。
那 \(c\) 如何比较?我们考虑用树状数组维护一下这谁能想得出来啊www
那这事就好办了,比完 \(b\) 之后就把它以 \(c\) 为下标出现次数为值存到树状数组里不就得了吗,OK,大功告成!

  • 芝士代码
#include <iostream>
#include <algorithm> 

using namespace std;
const int Max = 2e5+10;

int n , k , maxx , len , tot;
int ans[Max] , t[4*Max];

struct zx {
	int a , b , c , cnt , ans;
}p[Max] , s[Max];

bool cmp (zx x , zx y) {
	if(x.a == y.a) {
		if(x.b == y.b) return x.c < y.c;
		else return x.b < y.b;
	}
	else return x.a<y.a;
}

bool cmp1 (zx x , zx y) {
	if(x.b == y.b) return x.c < y.c;
	return x.b < y.b;
}

int lowbit(int x) {
	return x & (-x);
}

void add(int x , int y) {
	for(int i = x; i <= k; i += lowbit(i)) t[i] += y;
}

int ask(int x) {
	int res = 0;
	for(int i = x; i >= 1; i -= lowbit(i)) res += t[i];
	return res;
}

void cdq(int l , int r) {
	if(l == r) return;
	int mid = l + r >> 1;
	cdq(l , mid);
	cdq(mid+1 , r);
	sort(s+l , s+mid+1 , cmp1);
	sort(s+mid+1 , s+r+1 , cmp1);
	int j , i = l;
	for(int j = mid+1 ; j <= r; j++) {
		while(i <= mid && s[j].b >= s[i].b) {
			add(s[i].c , s[i].cnt);
			i++;
		}
		s[j].ans += ask(s[j].c);
	}
	for(int kk = l; kk < i; kk++) add(s[kk].c , -s[kk].cnt); 
}

int main() {
	cin >> n >> k;
	maxx = k;
	for(int i = 1; i <= n; i++) cin >> p[i].a >> p[i].b >> p[i].c;
	sort(p+1 , p+n+1 , cmp);
	for(int i = 1; i <= n; i++) {
		tot++;
		if(p[i+1].a != p[i].a || p[i+1].b != p[i].b || p[i+1].c != p[i].c) {
			s[++len].a = p[i].a;
			s[len].b = p[i].b;
			s[len].c = p[i].c;
			s[len].cnt = tot;
			tot = 0;
		}
	}
	cdq(1 , len);
	for(int i = 1; i <= len; i++) ans[s[i].ans+s[i].cnt-1] += s[i].cnt;
	for(int i = 0; i < n; i++) cout << ans[i] << endl;
	return 0;
}

标签:return,int,Max,分治,mid,kk,cdq
From: https://www.cnblogs.com/roselu/p/17572205.html

相关文章

  • 20230626-树链剖分+点分治
    20230626重链剖分计算每个节点子树大小,判断出每个点的重儿子优先遍历重儿子连边,并且按照DFS序重新编号特点:每条重链上的点编号是连续的每个点为根的子树内所有点的编号是连续的$\to$线段树需求:对于树上两点\(x,y\)路径上的所有点进行操作必然不能避免的事情......
  • 点分治 - 知识点梳理
    分治是一种将大的问题拆分成更小的问题并分而治之的算法,有利于使一个大的问题迅速缩小。在线性区间上的分治一般从区间中点将区间一分为二(这个中点也叫做分治中心),这样分\(\logn\)次就能使区间大小缩小到\(1\)。而在树上的分治一般以树的重心作为分治中心,这样分\(\logn\)次......
  • 分治法处理大整数相乘问题
    分治法解决大整数相乘问题1.题目描述大数乘法法运算跟一般的减法运算是不同的,在面对基本数据类型容量有限而导致无法存储特大数字的情况下,本文采用分治策略的方法来解决大数减运算问题。输入:两个代表整数的字符串a和b,规定a>=b,a,b>0。输出:返回表示结果整数的字符串。2.解决......
  • 线段树分治结构
    目录线段树分治结构基本知识:例题1: 模板(基础题)例题2: dp(背包)(会了就掌握题)线段树分治结构基本知识:应用点: 当有些东西一会出现,一会又不出现时,可以使用线段树分治方式: 维护某一个东西出现的时间段,并在线段树上打上标记,并dfs遇到标记后,就相当于加入了这个物品。当dfs到叶子节点后,就......
  • 树分治
    点分治回想一下在序列上的二分治:每次选择序列中点,递归处理两个子序列,处理跨过两个序列的信息。前两步保证了复杂度,第三步往往是解决问题的关键,那么这个思路能不能搬到树上呢?答案是肯定的,树分治思路和序列分治类似,我们每次递归处理子树,统计子树间的答案..,初步建立起模型后还有一......
  • 分治FFT
    考虑一下递推式:\[f_{i}=\sum\limits_{j=1}^ig_jf_{i-j}\]如果要暴力计算的话复杂度是\(n^2\),考虑到后面的是卷积的形式,但是唯一的问题是\(f\)自己得出自己。考虑分治。设当前分治区间为\(l,r\),首先分治计算\(l,mid\)的所有\(f\)值,然后考虑\(l,mid\)给\(mid+1,r\)......
  • CDQ 分治
    CDQ分治的思想最早由IOI2008金牌得主陈丹琦在高中时整理并总结,因此得名。适用范围多用于统计有特征的点对\((i,j)\)的数量或找出有特征的点对。流程对于一个区间\([L,R]\)中的点对\((i,j)\)(\(L\lei<j\leR\)),考虑分为三部分(\(mid=\frac{L+R}2\)):\(L\lei<j\lemid\)......
  • cdq分治学习笔记
    做着做着cdq分治的题发现自己太菜了写不出来题XD,所以来写写学习笔记。CDQ分治CDQ分治一般有两个用途:解决偏序问题、将动态问题转化为静态问题。偏序问题我们先来介绍第一个问题:偏序问题。普通的二维偏序就类似于逆序对,每个元素有两个属性\(a_i,b_i\),我们需要统计\(a_......
  • 6307: 网线主管 二分/分治
    描述 仙境的居民们决定举办一场程序设计区域赛。裁判委员会完全由自愿组成,他们承诺要组织一次史上最公正的比赛。他们决定将选手的电脑用星形拓扑结构连接在一起,即将它们全部连到一个单一的中心服务器。为了组织这个完全公正的比赛,裁判委员会主席提出要将所有选手的电脑等距离......
  • 【树分治】HDOJ 5016
    先预处理出每个点的最近点。。。。然后考虑固定根,对于每个根,从根到子树的路径中任选两条,如果dis[i]+dis[j]<w[j]。那么i就是j的一个合法点。。。。然后递归处理子树即可。。。。扩栈才过的。。。#include<iostream>#include<queue>#include<stack>#include<map>#includ......