P3157 [CQOI2011]动态逆序对 CDQ分治

一道CDQ分治模板题
简单来说,这道题是三维数点
对于离线的二维数点,我们再熟悉不过:利用坐标的单调递增性,先按更坐标排序,再按纵坐标排序
更新和查询时都直接调用纵坐标。
实际上,我们是通过排序将二维中的一维给消掉了。
那么,对于题中的三维数点,我们可以先按 $x$ 排序,以 $x$ 为标准进行分治
在分治的过程中,分别对左右区间按 $y$ 来排序。
由于左面的 $x$ 坐标一定是小于右面的 $x$ 坐标的。
所以这一维可以被我们消掉。
剩下的就是一个二维数点问题了,只需按照顺序依次更新 $z$ 即可。
(反正左面的 $x$ 比右面小,而且 $y$ 也一定比右面小,只要 $z$ 比右面小是都能统计出来的)

Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#define setIO(s) freopen(s".in","r",stdin) ,freopen(s".out","w",stdout) 
#define maxn 1000006
using namespace std;
int n,m,idx,place[maxn],C[maxn]; 
long long ans[maxn]; 
struct BIT{
    int lowbit(int x) { return x&(-x); }
    void add(int pos,int x){ 
        while(pos<=n) C[pos]+=x,pos+=lowbit(pos);  
    } 
    int ask(int pos){
        int sum=0;
        while(pos>0) sum+=C[pos],pos-=lowbit(pos); 
        return sum; 
    }
}tree;
struct OPT{
    int x,y,z,rnk,kind,id; 
}opt[maxn],tmp[maxn]; 
bool cmp(OPT i,OPT j)
{
    return (i.x==j.x&&i.y==j.y)?(i.rnk<j.rnk):((i.x==j.x)?i.y<j.y:i.x<j.x);    
} 
void solve(int L,int R)
{
    if(L>=R) return; 
    int mid=(L+R)>>1,tl=L-1,tr=mid; 
    for(int i=L;i<=R;++i){
        if(opt[i].rnk<=mid&&opt[i].kind==1) tree.add(opt[i].y,opt[i].z); 
        if(opt[i].rnk>mid&&opt[i].kind==2)  ans[opt[i].id]+=tree.ask(opt[i].y)*opt[i].z;  
    }
    for(int i=L;i<=R;++i) 
        if(opt[i].rnk<=mid&&opt[i].kind==1) tree.add(opt[i].y,-opt[i].z);
    for(int i=L;i<=R;++i) {
        if(opt[i].rnk<=mid) tmp[++tl]=opt[i];
        else tmp[++tr]=opt[i];
    }
    for(int i=L;i<=R;++i) opt[i]=tmp[i]; 
    solve(L,mid),solve(mid+1,R); 
}
int main(){
    //setIO("input");
    scanf("%d%d",&n,&m);
    for(int i=1,a;i<=n;++i)
    {
        scanf("%d",&a);
        opt[++idx].x=i;
        opt[idx].y=a;
        opt[idx].z=1;
        opt[idx].kind=1;
        opt[idx].rnk=idx; 
        place[a]=i; 
        tree.add(a,1); 
        ans[1]+=i-tree.ask(a); 
    }
    for(int i=1;i<=n;++i) tree.add(i,-1); 
    for(int i=1,a;i<=m;++i){
        scanf("%d",&a);
        opt[++idx].x=place[a];
        opt[idx].y=n;
        opt[idx].z=-1;
        opt[idx].kind=2;
        opt[idx].rnk=idx;
        opt[idx].id=i+1;

        opt[++idx].x=n;
        opt[idx].y=a;
        opt[idx].z=-1;
        opt[idx].kind=2;
        opt[idx].rnk=idx;
        opt[idx].id=i+1;

        opt[++idx].x=place[a];
        opt[idx].y=a;
        opt[idx].z=2;
        opt[idx].kind=2;
        opt[idx].rnk=idx;
        opt[idx].id=i+1; 

        opt[++idx].x=place[a];
        opt[idx].y=a;
        opt[idx].z=-1;
        opt[idx].kind=1; 
        opt[idx].rnk=idx;
    }
    sort(opt+1,opt+1+idx,cmp); 
    solve(1,idx); 
    for(int i=2;i<=m;++i) ans[i]+=ans[i-1]; 
    for(int i=1;i<=m;++i) printf("%lld
",ans[i]); 
    return 0; 
}

  

原文地址:https://www.cnblogs.com/guangheli/p/10257009.html