bzoj 3295 动态逆序对 (三维偏序,CDQ+树状数组)

链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3295

思路:

可以将这道题看成倒着插入,这样就可以转化成求逆序对数,用CDQ分治降维,正反用树状数组求两遍逆序对就好了。

这道题还可以用在线的树套树或者可持久化线段树来写。。

实现代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int M = 2e5+10;
struct node{
     int t,x,y;
     int kind,id;
     node() {}
     node(int a,int b,int c,int d,int e = 0):t(a),x(b),y(c),kind(d),id(e){}
     bool operator < (const node &k) const {
         if(x == k.x) return y<k.y;
         return x < k.x;
     }
};
int n,m,a[M],pos[M],x,c[M],tim,len;
node q[M],t[M];
ll ans[M];
void add(int x,int val){
     while(x <= n){
         c[x] += val;
         x += (x&-x);
     }
}

int getsum(int x){
    int sum = 0;
    while(x){
        sum += c[x];
        x -= (x&-x);
    }
    return sum;
}

void cdq(int l,int r){
    if(l == r) return ;
    int mid = (l + r) >> 1;
    for(int i = l;i <= r;i ++){
        if(q[i].t <= mid) add(q[i].y,q[i].kind);
        else ans[q[i].id] += q[i].kind*(getsum(n) - getsum(q[i].y));
    }
    for(int i = l;i <= r;i ++)
        if(q[i].t <= mid) add(q[i].y,-q[i].kind);

    for(int i = r;i >= l;i --){
        if(q[i].t <= mid) add(q[i].y,q[i].kind);
        else ans[q[i].id] += q[i].kind*getsum(q[i].y-1);
    }
    for(int i = l;i <= r;i ++)
        if(q[i].t <= mid) add(q[i].y,-q[i].kind);

    int L = l,R = mid+1;
    for(int i = l;i <= r;i ++){
        if(q[i].t <= mid) t[L++] = q[i];
        else t[R++] = q[i];
    }
    for(int i = l;i <= r;i ++) q[i] = t[i];
    cdq(l,mid); cdq(mid+1,r);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i ++){
        scanf("%d",&a[i]);
        pos[a[i]] = i; q[++len] = node(++tim,i,a[i],1,0);
    }
    for(int i = 1;i <= m;i ++){
        scanf("%d",&x);
        q[++len] = node(++tim,pos[x],x,-1,i);
    }
    sort(q+1,q+1+len);
    cdq(1,len);
    for(int i = 1;i <= m;i ++){
        ans[i] += ans[i-1];
        printf("%lld\n",ans[i-1]);
    }
    return 0;
}

 

posted @ 2018-08-23 13:34  冥想选手  阅读(172)  评论(0编辑  收藏  举报