CDQ分治解决这个问题:三维偏序
如果是一维偏序:排序
二维:双关键字排序,然后用树状数组维护
也可以分治(类似归并排序)
第一步一样
然后分类讨论
1.都在左边:递归处理
2.都在右边:递归处理
3.一左一右:因为归并过程期间,可以排序,所有可以用双指针
三维:
1.三关键字排序
然后分类讨论
1.都在左边:递归处理
2.都在右边:递归处理
3.一左一右:归并同时排序,然后双指针,然后树状数组
如果完全相等要去重,最后答案再加上
1.老C的任务:点权,询问矩阵里面的点权和
根据二维前缀和,我们只需要知道某个点的左下角的所有点总和
那就要求xi<=xj,y−i<=yj,zi<=zj
2.动态逆序对:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
int n,m;
struct Data
{
int a,t,res;
}q[N],w[N];
int tr[N],pos[N];
LL ans[N];
int lowbit(int x)
{
return x & -x;
}
void add(int x, int c) // 位置x加c
{
for (int i = x; i <N; i += lowbit(i)) tr[i] += c;
}
int query(int x) // 返回前x个数的和
{
int res = 0;
for (int i = x; i; i -= lowbit(i)) res += tr[i];
return res;
}
void merge_sort(int l,int r)
{
if(l>=r) return;
int mid=l+r>>1;
merge_sort(l,mid),merge_sort(mid+1,r);
int i=mid,j=r;
while(i>=l&&j>mid)
if(q[i].a>q[j].a) add(q[i].t,1),i--;
else q[j].res+=query(q[j].t-1),j--;
while(j>mid) q[j].res+=query(q[j].t-1),j--;
for(int k=i+1;k<=mid;k++) add(q[k].t,-1);
j=l,i=mid+1;
while(j<=mid&&i<=r)
if(q[i].a<q[j].a) add(q[i].t,1),i++;
else q[j].res+=query(q[j].t-1),j++;
while(j<=mid) q[j].res+=query(q[j].t-1),j++;
for(int k=mid+1;k<i;k++) add(q[k].t,-1);
i=l,j=mid+1;
int k=0;
while(i<=mid&&j<=r)
if(q[i].a<=q[j].a) w[k++]=q[i++];
else w[k++]=q[j++];
while(i<=mid) w[k++]=q[i++];
while(j<=r) w[k++]=q[j++];
for(int i=l,j=0;j<k;i++,j++) q[i]=w[j];
}
int main()
{
scanf("%d%d", &n, &m);
for(int i=0;i<n;i++)
{
scanf("%d", &q[i].a);
pos[q[i].a]=i;//映射
}
for(int i=0,j=n;i<m;i++)
{
int a;
scanf("%d", &a);
q[pos[a]].t=j--;//时间戳
pos[a]=-1;
}
for(int i=1,j=n-m;i<=n;i++)
if(pos[i]!=-1)//如果当前位置没被用过
q[pos[i]].t=j--;
merge_sort(0,n-1);
for(int i=0;i<n;i++) ans[q[i].t]=q[i].res;
for(int i=2;i<=n;i++) ans[i]+=ans[i-1];
for(int i=0,j=n;i<m;i++,j--) printf("%lld\n",ans[j]);
return 0;
}