偏序

(其实,,,我是来学二维偏序的,,,结果被卿姐的视频(尽管这次主讲人不是卿姐)带偏了,,结果就都学了,,,)

既然要学习多维偏序,那就先看一下偏序是个什么鬼吧,,,,

偏序:

给定一个集合 S S S,“ ≤ ≤ ”是 S S S上的二元关系,若“ ≤ ≤ ”满足:
1.自反性: ∀ a ∈ S ∀a∈S aS,有 a ≤ a a≤a aa
2.反对称性:∀a,b∈S, a ≤ b a≤b ab b ≤ a b≤a ba,则 a = b a=b a=b
3.传递性: ∀ a , b , c ∈ S , a ≤ b ∀a,b,c∈S,a≤b abcSab b ≤ c b≤c bc,则 a ≤ c a≤c ac
则称“ ≤ ≤ ”是 S S S上的非严格偏序或自反偏序。
(可以手动百度百科一下:偏序)

知道什么是偏序后就来考虑一下怎么搞定偏序问题:

1.一维偏序:

(很显然,不就是个sort嘛,,不多说了)

2.二维偏序:

这个要想一下了,放一个二维偏序的板子题:Laptop
二维偏序就可以看作是一个坐标轴中的点(x,y)就是查找有多少个点x,y都比该点小。
这个,做过最长上升子序列,就知道怎么坐了,
先按x排个序,再倒着枚举树状数组求后缀和,树状数组更新即可。

放代码:

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
    return s*w;
}
const int sea=1e5+7;
struct hit{int x,y;}a[sea];
int n,lb,b[sea],c[sea];
bool cmp(hit a,hit b){return a.x<b.x;}
int lowbit(int x){return x&-x;}
void add(int x){for(int i=x;i<=sea;i+=lowbit(i)) c[i]++;}
int ask(int x){int ans=0;for(int i=x;i;i-=lowbit(i))ans+=c[i];return ans;}
int main()
{
    n=read();
    for(int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(),b[i]=a[i].y;
    sort(b+1,b+n+1); lb=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++) a[i].y=lower_bound(b+1,b+lb+1,a[i].y)-b;
    sort(a+1,a+n+1,cmp);
    int ans=0;
    for(int i=n;i>=1;i--)
    {
        int ins=ask(a[i].y);
        if(n-i-ins!=0) ans++;
        add(a[i].y);
    }
    printf("%d",ans);
    return 0;
}
3.三维偏序:

既然二维偏序都会了,就来看一下三维偏序吧,,
给你三个维度你怎么办呢,,,

引入一个新知:CDQ分治(陈丹琪分治)
CDQ分治,好东西啊,这个没有什么固定的板子,是个比较巧的思想。
先介绍一下CDQ的基本思想:
当对于一个序列来说,如果说你已经处理好了前面一部分的结果,你就可以用前面一部分的信息去处理对后面所造成的影响,
(尽管它叫CDQ分治,但是我觉得和分治的中心思想其实差不多,也有大佬说:不是她发明的,这就是分治,只不过是因为cdq将她推广了起来)
这样的话,,我们就可以对第一维进行CDQ分治,第二维树状数组,第三维就sort即可,,
放个例题(经典的板子题):陌上花开
代码:

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
    return s*w;
}
const int sea=2e5+7;
struct hit{
	int x,y,z,id,cnt,ans;
	bool operator==(hit A) const {return x==A.x&&y==A.y&&z==A.z;} 
}a[sea],b[sea];
int nn,n,k,c[sea];
bool cmp1(hit a,hit b){return a.x<b.x||(a.x==b.x&&(a.y<b.y||(a.y==b.y)&&(a.z<b.z)));}
bool cmp2(hit a,hit b){return a.y<b.y||(a.y==b.y&&(a.z<b.z||(a.z==b.z)&&(a.x<b.x)));}
int lowbit(int x){return x&-x;}
void add(int x,int a){for(int i=x;i<=k;i+=lowbit(i)) c[i]+=a;}
int ask(int x){int s=0;for(int i=x;i;i-=lowbit(i)) s+=c[i];return s;}
void CDQ(int L,int R)
{
	if(L==R) return ;
	int mid=(L+R)/2; CDQ(L,mid);CDQ(mid+1,R);
	sort(a+L,a+R+1,cmp2);
	for(int i=L;i<=R;i++)if(a[i].id<=mid) add(a[i].z,a[i].cnt); else a[i].ans+=ask(a[i].z);
	for(int i=L;i<=R;i++) if(a[i].id<=mid) add(a[i].z,-a[i].cnt); 	
}
int main()
{
	nn=read(); k=read(); n=0;
	for(int i=1;i<=nn;i++) b[i].x=read(),b[i].y=read(),b[i].z=read();
	sort(b+1,b+nn+1,cmp1); 
	for(int i=1;i<=nn;i++) 
	if(b[i]==a[n]) a[n].cnt++;
	else a[++n]=b[i],a[n].cnt=1,a[n].id=n;
	CDQ(1,n);
	sort(a+1,a+1+n,cmp1);
	for(int i=1;i<=n;i++) c[a[i].cnt+a[i].ans]+=a[i].cnt;
	for(int i=1;i<=nn;i++) printf("%d\n",c[i]);
	return 0;
}
4.四维偏序:

直接放题了:

题目链接:Star
题意:询问三维空间中的两颗星星之间的星星,单点插入,区间查询。
题解:
(尽管是四维偏序的板子题,,,我还是敲了快两个小时,,,)
还是套路:一维,二维CDQ分治,三维树状数组,四维sort。
但是这道题还是要用点容斥的,因为是两个三维星星之间,所以对于询问要容斥处理一下。
代码:

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
inline int read()
{
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
    return s*w;
}
struct hit
{
	int x,y,z,typ,id;
	hit (int xx,int yy,int zz,int tt,int ii):x(xx),y(yy),z(zz),typ(tt),id(ii) {}
	hit (){}
}; 
const int sea=5e4+7;
const int pool=1e5+7;
vector<hit>v,v2,v3;
vector<int>lsh;
int T,n,m,ans[sea],c[pool],vis[sea]; 
bool cmpv2(hit a,hit b){if(a.x==b.x) return a.id<b.id;else return a.x<b.x;}
bool cmpv3(hit a,hit b){if(a.y==b.y) return a.id<b.id;else return a.y<b.y;}
int lowbit(int x){return x&-x;}
void add(int x,int a){for(int i=x;i<pool;i+=lowbit(i)) c[i]+=a;}
int ask(int x){int s=0;for(int i=x;i;i-=lowbit(i)) s+=c[i];return s;}
void Star()
{
	for(int i=0;i<v3.size();i++)
	{
		if(v3[i].typ==0) add(v3[i].z,1); 
		else 
		{
			int t=ask(v3[i].z);
			ans[v3[i].id]+=t*v3[i].typ;
		}
	}
	for(int i=0;i<v3.size();i++) if(v3[i].typ==0) add(v3[i].z,-1);
}
void CDQ2(int l,int r)
{   
	if(l>=r) return ;
	int mid=(l+r)/2;
	CDQ2(l,mid); v3.clear();
	for(int i=l;i<=mid;i++) if(v2[i].typ==0) v3.push_back(v2[i]);
	for(int i=mid+1;i<=r;i++) if(v2[i].typ!=0) v3.push_back(v2[i]);
	sort(v3.begin(),v3.end(),cmpv3);
	Star();
	CDQ2(mid+1,r);
}
void CDQ(int l,int r)
{
	if(l>=r) return ;
	int mid=(l+r)/2;
	CDQ(l,mid); v2.clear();
	for(int i=l;i<=mid;i++) if(v[i].typ==0) v2.push_back(v[i]);
	for(int i=mid+1;i<=r;i++) if(v[i].typ!=0) v2.push_back(v[i]);
	sort(v2.begin(),v2.end(),cmpv2);
	CDQ2(0,v2.size()-1);
	CDQ(mid+1,r);
}
int main()
{ 
	T=read(); 
	while(T--)
	{
		memset(ans,0,sizeof(ans));
		memset(c,0,sizeof(c));
		memset(vis,0,sizeof(vis));
		v.clear(); lsh.clear();
		n=read();
		for(int i=0;i<n;i++)
		{
			int op=read();
			if(op==1)
			{
				int x=read(),y=read(),z=read();
				v.push_back(hit(x,y,z,0,i)); 
				lsh.push_back(z);	
			}
			else 
			{
				vis[i]=1;
				int xa=read(),ya=read(),za=read(),xb=read(),yb=read(),zb=read();
				v.push_back(hit(xa-1,ya-1,za-1,-1,i));			
				v.push_back(hit(xa-1,ya-1,zb,1,i));			
				v.push_back(hit(xa-1,yb,za-1,1,i));			
				v.push_back(hit(xa-1,yb,zb,-1,i));	
				v.push_back(hit(xb,ya-1,za-1,1,i));			
				v.push_back(hit(xb,ya-1,zb,-1,i));			
				v.push_back(hit(xb,yb,za-1,-1,i));			
				v.push_back(hit(xb,yb,zb,1,i));	
				lsh.push_back(za-1); lsh.push_back(zb);		
			}
		}
		sort(lsh.begin(),lsh.end()); auto it=unique(lsh.begin(),lsh.end());//auto是比较松的定义类型,可以对你所赋的初值进行自行定义类型,但是只有在c++.11中可以通过编译,可以自行百度依下。
		lsh.resize(distance(lsh.begin(),it));
		for(int i=0;i<v.size();i++) v[i].z=lower_bound(lsh.begin(),lsh.end(),v[i].z)-lsh.begin()+1;
		CDQ(0,v.size()-1);
		for(int i=0;i<n;i++) if(vis[i]) printf("%d\n",ans[i]);
	}
	return 0;
}

以为只有四维就最高了????
你想吧,,,,( ̄ェ ̄;)

4.五维偏序及以上

北京的一道十六维偏序就死了好多人,,,,
放一下链接:上天的卿学姐(十六维偏序)
但其实是分块+CDQ分治+树状数组即可
据dalao说都是用分块写的,,而且还很简单,,
(我这个蒟蒻就再去好好学学,学会了马上补,,一定补!(心虚))

遇见你之前,我可是风中一匹狼。遇见你之后,变成了一只可爱的小奶狗。

可是,这世上哪有小奶狗啊,全都是动了心的孤狼。——Blng

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值