首页 > 其他分享 >三位偏序,CDQ分治入门

三位偏序,CDQ分治入门

时间:2023-12-29 14:55:19浏览次数:26  
标签:偏序 树状 ll 分治 mid CDQ 数组 排序

(我发现我最近dp没有进展,导致我开始刷水题了。。)
cdp分治,我蓝书又又看不懂了
所以我还是自己去找题目做的
看了看,这个应该才算是真正的入门吧

这里先放上一句我觉得非常重要的话吧

CDQ分治有一个重要的思想——用一个子问题来计算对另一个子问题的贡献。

看到最后我对这句话的理解会又多少吧
二维偏序非常简单,就是排序+树状数组,排序先维护了一维,从第一维上保证了答案的有效性,树状数组以下标统计保证了第二维
逆序对统计就是二位偏序,这是树状数组的入门题和经典运用

那么三位偏序呢?
很明显,三位偏序需要在统计的时候再通过一些方式来保证树状数组中被加入的是合法的,也就是\(a[i]<a[j],b[i]<b[j]\)同时成立,而第三维由树状数组来保证。

我们考虑让第一维的维护方法不变,依旧是以\(a[i]\)为第一关键字进行排序。
然后再此基础上,以\(b[i]\)为第一关键字进行归并排序的过程
考虑这个过程的某一个阶段,此时,以这个区间的中间作为分界线,这个分界线的左边和右边已经分别以\(b[i]\)作为关键字排序完毕了,但是整体还没有以\(b[i]\)为关键字进行全部的排序(只要把左右两边合并一下就是全部排序完毕了),这个时候,因为先前的排序,左边的数字的\(a[i]\)和右边的数字的\(a[i]\)相比,一定是更小的,也就是如果左边的数字和右边的数字的\(b[i]\)也满足条件,那就可以放进树状数组里面进行答案的统计了,这个时候的数组,只有这个分界线左边的数字可能能和右边的数字产生贡献,我们只需要在此基础上找到合法的\(b[i]\)的组合就可以了
大致过程就是这个。。很抽象,我理解了挺久的

我归并排序的写法写挂了
其实没必要归并排序,直接对每一个小区间用sort,复杂度不变

额,有一些细节,就是去重,这个就自己考虑吧

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read() {
	char c=getchar();ll a=0,b=1;
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
ll n,tot,k,tr[200001],a[200001],b[200001],c[200001],v[200001],q[200001],p[200001],cnt[200001],ans[200001];
inline ll lowbit(ll x)
{
	return x&(-x);
}
bool mycmp(ll x,ll y)
{
    return a[x]<a[y]||(a[x]==a[y]&&(b[x]<b[y]||(b[x]==b[y]&&c[x]<c[y])));
}
bool mycmp2(ll x,ll y)
{
	if(b[x]==b[y])return c[x]<c[y];
	return b[x]<b[y];
}
inline void add(ll i,ll x)
{
	while(i<=k)
	{
		tr[i]+=x;
		i+=lowbit(i);
	}
}
inline ll ask(ll i)
{
	ll ans=0;
	while(i>0)
	{
		ans+=tr[i];
		i-=lowbit(i);
	}
	return ans;
}
void cdq(ll l,ll r)
{
	if(l==r)return ;
	ll mid=(l+r)>>1;
	cdq(l,mid);cdq(mid+1,r);
	sort(p+l,p+mid+1,mycmp2);
	sort(p+mid+1,p+r+1,mycmp2);
	ll i=mid+1,j=l;
	while(i<=r)
	{
		while(b[p[j]]<=b[p[i]]&&j<=mid)
		{
			add(c[p[j]],v[p[j]]);
			j++;
		}
		cnt[p[i]]+=ask(c[p[i]]);
		i++;
	}
	for(ll i=l;i<j;i++)
	{
		add(c[p[i]],-v[p[i]]);
	}
}
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n=read();k=read();
	for(ll i=1;i<=n;i++)
	{
		a[i]=read();b[i]=read();c[i]=read();
		p[i]=i;
	}
	sort(p+1,p+1+n,mycmp);ll tot=1;
	for(ll i=2;i<=n;i++)//ºÃ¼ò½àµÄÈ¥ÖØ 
	{
		ll x=p[i],y=p[tot];++v[y];
		if(a[x]!=a[y]||b[x]!=b[y]||c[x]!=c[y])p[++tot]=x;
	}
	v[p[tot]]++;
	cdq(1,tot);
	for(ll i=1;i<=tot;i++)
	{
		ans[cnt[p[i]]+v[p[i]]-1]+=v[p[i]];
	}
	for(ll i=0;i<n;i++)
	{
		cout<<ans[i]<<endl;
	}
	return 0;
}

总算是写过了。。。
这么简单的题目啊

不得不说,跳出舒适圈还是挺不舒服的,写dp多爽啊。。。

标签:偏序,树状,ll,分治,mid,CDQ,数组,排序
From: https://www.cnblogs.com/HLZZPawa/p/17934873.html

相关文章

  • 【学习笔记】边分治
    算法思想和点分治类似,边分治每次选一条边,考虑跨过这条边的路径贡献,为了保证复杂度,会让两边子树大小尽量接近。发现菊花图无论怎么分治都是无效的,考虑将原树三度化,具体做法是如果\(u\)有两个儿子,就新建一个节点连接第二个儿子,如果还有更多的儿子,就再新建节点与上一次新建的节......
  • 边分治
    namespaceBFZ{ intk=1,ssz,rt,tot; inth[N],dep[N],sz[N],vis[N]; vector<pair<int,int>>G[N]; structAB{ inta,b,c,n; }d[N*2]; voidcun(intx,inty,intz){ d[++k]={x,y,z,h[x]},h[x]=k; } voidrebuild(intx,intfa){ inttmp=0,lst=0......
  • 递归与分治
    一、初步递归1、递归特点函数自己调用自己存在直接递归和间接递归一定有退出条件2、递归三要素退出条件递归函数的定义最后的解3、递归优化记录重复的值(存在重复的值才记录)......
  • 【分治查找数组的最大次大元素】
    分治算法介绍分治算法是一种将问题分解成更小子问题,解决子问题,然后将它们的结果合并以解决原始问题的方法。对于查找数组的最大和次大元素,我们可以将数组分成两部分,然后分别查找每个子数组的最大和次大元素,最后将这些结果合并以得到原始数组的最大和次大元素。算法步骤如果数......
  • CDQ分治
    CDQ分治一般珂以替代一些较复杂的高级数据结构,能用来处理偏序问题、优化dp转移等。大概思路就是分治处理点对的关系,分成三类点:\(\mathbf{\small{1}}\lei<j\lemid\)、\(\mathbf{\small{1}}\lei\lemid<j\len\)、\(mid<i<j\len\),然后用额外的\(O(logn)\)的时间去计算第二类......
  • 归并分治
    归并排序是计算机之父"冯·诺依曼"发明的,但这其中隐藏了一种归并分治的思想。这种思想在一些题目中会帮助我们解决很多问题。原理对于一个大问题的答案,如果等于左边子问题的答案+右边子问题的答案+跨越左右问题的答案。在计算跨越左右问题的答案时,左右两边是有序的是否会......
  • 【合并排序链表】分治/优先队列
    合并两个排序链表模拟维护一个合并链表,每次添加两个排序链表中较小val的节点即可模拟代码publicListNodemergeTwo(ListNodea,ListNodeb){if(a==null)returnb;if(b==null)returna;ListNodeans=newListNode(0);Lis......
  • 241. 为运算表达式设计优先级(分治 +记忆化)
    Problem:241.为运算表达式设计优先级给你一个由数字和运算符组成的字符串expression,按不同优先级组合数字和运算符,计算并返回所有可能组合的结果。你可以按任意顺序返回答案。生成的测试用例满足其对应输出值符合32位整数范围,不同结果的数量不超过示例1:输入:expression=......
  • [持续更新][数据结构][算法]涵盖线性表、栈、链表、队列、图、动态规划、分治递归、回
    备考考点整理内部排序表格树的主要考点二叉树的常考紧紧抓住\(n_0=n_2+1\)\(n=n_0+n_1+n_2...n_m\)\(n=n_1+2*n_2+3*n_3...m*n_m\)+1哈夫曼树没有度为1的结点,也就是\(n_1=0\)完全二叉树常考总结最大岛屿问题(dfs模板)#include<iostream>#include<algorith......
  • 树分治全家桶
    树分治全家桶树,(是种在路边的绿化植物)是图论当中的一种特殊图,(由于绿化环境作用非常优秀)由于特殊性质丰富,经常出现在我们身边。本文将主要讲述(如何植树)一种树上优美的暴力——树分治。树分治树分治可以将部分\(O(n^2)\)的暴力降至\(O(n\logn)\)级别,尤其适用于树上距离及其......