题面
最近米娜都在学cdq分治,看到题都直接想CDQ,还讲得头头是道,所以本蒟蒻也水一水。找到bzoj的一题果题,居然还是权限的,但我还是找到了本题。
个人理解,有一个修改和查询的序列,CDQ就是可以离线的条件下,用logN的复杂度,把动态的问题转化为静态的问题,即把边修改边查询改为先修改再查询。
主要思想大概是这样的,有一个询问和查询的序列区间[L,R],二分一个mid,先处理子问题[l,mid],再用与(R-L)相关的复杂度,处理[L,mid]中的修改对[mid+1,R]中的询问的影响,然后再处理区间[mid+1,R]。
题意就是有n个元素,每个元素有3个属性a,b,c。对于每一个元素问有多少个其他元素的3个属性都分别小于等于它的三维。
二维就是一个BIT求逆序对。
三维还是要先排序,然后套CDQ分治,现在有两个区间[L,mid],和[mid+1,R],由于[mid+1,R]的第一维都大于[L,mid],问题就变成了对于[mid+1,R]的每一个元素,[L,mid]有多少个元素的两维都小于它,就是一个权值BIT可以搞定了。
看起来非常简单,但我刚看到题的时候还是懵B的,听旁边的某犇吹了一会B才会一丢丢。
但这题是小于等于,并不是严格小于,原则上应该用两个数组,加入BIT时应把相同的都加进去再统计答案。但经过我的玄学思考,发现只要每次都按3关键字排序,就能解决大部分问题,但还有三维都相同的情况没有考虑。
显然三维相同答案必然也相同,而3关键字排序必然时它们排到了一起。可以由前到后去MAX,再由后往前去MAX,也许就可以了。
但还是Wa了,通过玩炉石,我发现了这可能是因为快排的不稳定性使得所有3维相同的元素的答案都不是正确答案,那么再人为控制排序的稳定性就可以A了。
复杂度大概是这样的
F(N)=F(N/2)*2+Nlog N=N(logN)^2
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const int N=100100;
struct yy
{
int a,b,c,num,now;
}f[N],g[N];
bool amp(yy x,yy y)
{
if(x.a==y.a&&x.b==y.b)
return x.c<y.c;
if(x.a==y.a)
return x.b<y.b;
return x.a<y.a;
}
bool bmp(yy x,yy y)
{
if(x.b==y.b&&x.c==y.c)
return x.now<y.now;
if(x.b==y.b)
return x.c<y.c;
return x.b<y.b;
}
int n,m,ans[N],h[N];
int bit[2*N];
void add(int x,int ad)
{
for(;x<=m;x+=x&-x)
bit[x]+=ad;
}
int sum(int x)
{
int res=0;
for(;x;x-=x&-x)
res+=bit[x];
return res;
}
void work(int l,int r)
{
if(l==r)
return;
int mid=(l+r)/2;
work(l,mid);
for(int i=l;i<=r;i++)
g[i]=f[i];
sort(g+l,g+r+1,bmp);
for(int i=l;i<=r;i++)
if(g[i].now<=mid)
add(g[i].c,1);
else
ans[g[i].num]+=sum(g[i].c);
for(int i=l;i<=r;i++)
if(g[i].now<=mid)
add(g[i].c,-1);
work(mid+1,r);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&f[i].a,&f[i].b,&f[i].c);
f[i].num=i;
}
sort(f+1,f+n+1,amp);
for(int i=1;i<=n;i++)
f[i].now=i;
work(1,n);
for(int i=2;i<=n;i++)
if(f[i].a==f[i-1].a&&f[i].b==f[i-1].b&&f[i].c==f[i-1].c)
ans[f[i].num]=max(ans[f[i].num],ans[f[i-1].num]);
for(int i=n-1;i>=1;i--)
if(f[i].a==f[i+1].a&&f[i].b==f[i+1].b&&f[i].c==f[i+1].c)
ans[f[i].num]=max(ans[f[i].num],ans[f[i+1].num]);
for(int i=1;i<=n;i++)
h[ans[i]]++;
for(int i=0;i<n;i++)
printf("%d\n",h[i]);
return 0;
}