BZOJ3295 [CQOI2011]动态逆序对

Description

对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

Input

输入第一行包含两个整数nm,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
 

Output

 
输出包含m行,依次为删除每个元素之前,逆序对的个数。

Sample Input

5 4
1
5
3
4
2
5
1
4
2

Sample Output

5
2
2
1

样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。

HINT

N<=100000 M<=50000

正解:cdq分治或带修改主席树

解题报告:为了好好练练主席树,强行把这道cdq水题用带修改主席树做一遍

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#define RG register
#define ll long long
const int N = 10000000;
const int M = 200005;

using namespace std;

int gi(){
    RG char ch=getchar();RG int x=0;
    while(ch<'0' || ch>'9') ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}

struct dota{
    int l,r;
    int s;
}tr[N];

int rt[M],f[M],L[M],g[M],ra[M];
ll v[M],ans;
int n,m,cnt;
bool vis[M];

void build(int &x,int s,int l,int r){
    if (x==0) x=++cnt;
    ++tr[x].s;
    if (l==r) return;
    int mid=(l+r)>>1;
    if (s<=mid) build(tr[x].l,s,l,mid);
    else build(tr[x].r,s,mid+1,r);
    return;
}

void work(int x,int s){
    while(x<n){
        build(rt[x],s,1,n);
        x+=x&(-x);
    }
    return;
}

int check(int x,int l,int r,int ql,int qr){
    if (ql<=l && r<=qr) return tr[x].s;
    int mid=(l+r)>>1,ans=0;
    if (ql<=mid) ans+=check(tr[x].l,l,mid,ql,qr);
    if (qr>mid)  ans+=check(tr[x].r,mid+1,r,ql,qr);
    return ans;
}

ll query(int x,int l,int r){
    int k=0;ll s=0;
    while(x){
        L[++k]=rt[x];
        x-=x&(-x);
    }
    for (RG int i=1; i<=k; ++i)
        s+=check(L[i],1,n,l,r);
    return s;
}

int main(){
    n=gi()+1,m=gi();
    for (RG int i=1; i<n; ++i) f[i]=gi(),ra[f[i]]=i;
    for (RG int i=1; i<=m; ++i) g[i]=gi(),vis[g[i]]=1;
    for (RG int i=1; i<n; ++i) if (vis[f[i]]==0){
            ans+=query(i,f[i]+1,n);
            ans+=query(n-1,1,f[i]);
            ans-=query(i,1,f[i]);
            work(i,f[i]);
        }
    for (RG int i=m; i>=1; --i){
        int w=ra[g[i]];
        work(w,g[i]);
        ans+=query(w,g[i]+1,n);
        ans+=query(n-1,1,g[i]);
        ans-=query(w,1,g[i]);
        v[i]=ans;
    }
    for (RG int i=1; i<=m; ++i) printf("%lld\n",v[i]);
    return 0;
}

 

posted @ 2017-03-01 09:55  Cjk_2001  阅读(343)  评论(8编辑  收藏  举报