二維偏序&三維偏序的一些總結

二維偏序

數星星 https://loj.ac/problem/10114

大概就是先按第一維排個序,然後按第二維建個樹狀數組,值域爲下標,每次查詢之前的有幾個就行了(sum函數)

直接上代碼



#include <bits/stdc++.h>

using namespace std;
const int maxn=3.2*10005;
struct node
{
	int x,y;
}a[maxn];int c[maxn];int n,cnt[maxn];
int maxv=0;
int cmp(node x,node y)
{
	if(x.x!=y.x) return x.x<y.x;
	return x.y<y.y;
}
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int val)
{
	while(x<=maxv)
	{
		c[x]+=val;
		x+=lowbit(x);
	}
} 
int sum(int x)
{
	int s=0;
	while(x>0)
	{
		s+=c[x];
		x-=lowbit(x);
	}
	return s;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i].x,&a[i].y); 
		a[i].x+=1;a[i].y+=1;
		maxv=max(maxv,a[i].y);
		
	}
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++)
	{
		cnt[sum(a[i].y)]++;
		add(a[i].y,1);
	}
	for(int i=0;i<n;i++) cout<<cnt[i]<<endl;
	return 0;
}

三維偏序

在二維的基礎上加個分治就ok了。先全部按照x排序,然後進行分治。然後把每一次的答案+=到總答案裏

#include <bits/stdc++.h>

using namespace std;
int _n,k;
const int maxn=200005;
struct node
{
	int x,y,z,ans,w;
}a[maxn],b[maxn];int n;int c[maxn]; 
int ans[maxn];
int cmp(node x,node y)
{
	if(x.x!=y.x) return x.x<y.x;	
	if(x.y!=y.y) return x.y<y.y;
	return x.z<y.z;
}
int cmp1(node x,node y)
{
	if(x.y!=y.y) return x.y<y.y;	
	if(x.z!=y.z) return x.z<y.z;
	return x.x<y.x;
}
int lowbit(int x) {return x&(-x);}
void add(int x,int val)
{
	while(x<=k)
	{
		c[x]+=val;
		x+=lowbit(x);
	}
}
int sum(int x)
{
	int s=0;
	while(x>0)
	{
		s+=c[x];
		x-=lowbit(x);
	}
	return s;
}
void solve(int l,int r)
{
	if(l==r) return; 
	int mid=(l+r)/2;
	solve(l,mid);solve(mid+1,r);
	sort(a+l,a+mid+1,cmp1);sort(a+mid+1,a+r+1,cmp1);
	int i=mid+1;int j=l;
	for(;i<=r;i++)
	{
		while(a[j].y<=a[i].y&&j<=mid) add(a[j].z,a[j].w),j++;
		a[i].ans+=sum(a[i].z);
	}
	for(i=l;i<j;i++)
	{
		add(a[i].z,-a[i].w);//去掉痕跡! 
	}
}
int main()
{
	scanf("%d%d",&_n,&k);
	for(int i=1;i<=_n;i++) scanf("%d%d%d",&b[i].x,&b[i].y,&b[i].z);
	sort(b+1,b+1+_n,cmp);int tot=0;
	n=0;
	for(int i=1;i<=_n;i++)
	{
		tot++;
		if(b[i].x!=b[i+1].x||b[i].y!=b[i+1].y||b[i].z!=b[i+1].z)
            a[++n]=b[i],a[n].w=tot,tot=0;	
	}
	solve(1,n);
	for(int i=1;i<=n;i++) 
        ans[a[i].ans+a[i].w-1]+=a[i].w;
	for(int i=0;i<_n;i++) cout<<ans[i]<<endl;
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章