二維偏序
數星星 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;
}