bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)

Posted Swm_sxt

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)相关的知识,希望对你有一定的参考价值。

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
 
各种方法都可做
 
树套树(5.9s)
技术分享
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

int n,m,l,r,o,p,num=0;
long long ans=0;
inline int read(){
    p=0;o=getchar();
    while(o<0||o>9) o=getchar();
    while(o>=0&&o<=9) p=p*10+o-48,o=getchar();
    return p;
}
int root[100001],a[100001],tt[100001];
struct tree{
    int l,r,k;
    tree(){
        k=0;
    }
};
tree t[10000000];
inline void insert(int &p,int l,int r,int k){
    if (p==0) p=++num;
    t[p].k++;
    if (l==r) return;
    int mid=l+r>>1;
    if (k<=mid) insert(t[p].l,l,mid,k);else insert(t[p].r,mid+1,r,k);
}
inline void del(int p,int l,int r,int k){
    t[p].k--;
    if (l==r) return;
    int mid=l+r>>1;
    if (k<=mid) del(t[p].l,l,mid,k);else del(t[p].r,mid+1,r,k);
}
inline int qui(int p,int l,int r,int k){
    if (p==0) return 0;
    if (r==k) return t[p].k;
    int mid=l+r>>1;
    if (k<=mid) return qui(t[p].l,l,mid,k);else return qui(t[p].r,mid+1,r,k)+(t[p].l==0?0:t[t[p].l].k);
}
inline int qua(int p,int l,int r,int k){
    if (p==0) return 0;
    if (l==k) return t[p].k;
    int mid=l+r>>1;
    if (k<=mid) return qua(t[p].l,l,mid,k)+(t[p].r==0?0:t[t[p].r].k);else return qua(t[p].r,mid+1,r,k);
}
inline int lo(int x){return x&(-x);}
inline void in(int i,int k){
    while(i<=n){
        insert(root[i],1,n,k);
        i+=lo(i);
    }
}
inline void de(int i,int k){
    while(i<=n){
        del(root[i],1,n,k);
        i+=lo(i);
    }
}
inline long long ask(int x,int k){
    long long s=0;
    k++;
    while(x>0){
        if (k<=n) s+=qua(root[x],1,n,k);
        x-=lo(x);
    }
    return s;
}
inline long long aski(int x,int k){
    long long s=0;
    k--;
    while(x>0){
        if (k>=1) s+=qui(root[x],1,n,k);
        x-=lo(x);
    }
    return s;
}
int main(){
    register int i,j;
    n=read();
    m=read();
    for (i=1;i<=n;i++) in(i,a[i]=read()),tt[a[i]]=i;
    for (i=1;i<=n;i++) ans+=ask(i,a[i]);
    while(m--){
        printf("%lld\n",ans);
        l=read();r=tt[l];
        if (a[r]==0) continue;a[r]=0;
        ans-=ask(r,l)+aski(n,l)-aski(r,l);
        de(r,l);
    }
}
View Code

 

CDQ分治

 

技术分享
#include<cstdio>
#include<algorithm>
using namespace std;
int read_p,read_ca,pr_num,pr_ch[1000];
inline int read(){
    read_p=0;read_ca=getchar();
    while(read_ca<0||read_ca>9) read_ca=getchar();
    while(read_ca>=0&&read_ca<=9) read_p=read_p*10+read_ca-48,read_ca=getchar();
    return read_p;
}
inline void pr(long long k){
    pr_num=0;
    while(k>0) pr_ch[++pr_num]=k%10,k/=10;
    while(pr_num)
    putchar(pr_ch[pr_num--]+48);
    putchar(\n);
}
struct na{
    int x,y,t;
}b[100001],o[100001],y[100001];
int n,m,u[100001],ti[100001],s[100001];
long long ans[100001][2];
inline int low(int x){return x&(-x);}

inline void add(int x){
    while (x<=n){
        s[x]++;
        x+=low(x);
    }
}
inline void del(int x){
    while (x<=n){
        s[x]--;
        x+=low(x);
    }
}
inline int ask(int x){
    int ans=0;
    while (x>0){
        ans+=s[x];
        x-=low(x);
    }
    return ans;
}
inline bool cmp(na a,na b){
    if ((a.x==b.x)&&(a.y==b.y)) return a.t<b.t;
    if (a.x==b.x) return a.y>b.y;
    return a.x<b.x;
}
inline bool tmp(na a,na b){
    if ((a.x==b.x)&&(a.y==b.y)) return a.t<b.t;
    if (a.x==b.x) return a.y<b.y;
    return a.x>b.x;
}
inline void work0(int l,int r){
    if (l==r) return;
    int mid=l+r>>1,ll=l-1,rr=mid;
    for (register int i=l;i<=r;i++){
        if (b[i].t<=mid) add(n-b[i].y+1);
        if (b[i].t>mid) ans[b[i].t][0]+=ask(n-b[i].y+1);
    }
    for (register int i=l;i<=r;i++)
    if (b[i].t<=mid) o[++ll]=b[i];else o[++rr]=b[i];
    for (register int i=l;i<=r;i++) b[i]=o[i];
    for (register int i=l;i<=r;i++) if (b[i].t<=mid) del(n-b[i].y+1);
    work0(l,mid);work0(mid+1,r);
}
inline void work1(int l,int r){
    if (l==r) return;
    int mid=l+r>>1,ll=l-1,rr=mid;
    for (register int i=l;i<=r;i++){
        if (y[i].t<=mid) add(y[i].y);
        if (y[i].t>mid) ans[y[i].t][1]+=ask(y[i].y);
    }
    for (register int i=l;i<=r;i++) if (y[i].t<=mid) del(y[i].y);
    for (register int i=l;i<=r;i++)
    if (y[i].t<=mid) o[++ll]=y[i];else o[++rr]=y[i];
    for (register int i=l;i<=r;i++) y[i]=o[i];
    work1(l,mid);work1(mid+1,r);
}
int main(){
    register int i,j=0;
    n=read();m=read();
    for (i=1;i<=n;i++) u[read()]=i;
    for (i=0;i<m;i++) ti[read()]=m-i;
    for (i=1;i<=n;i++){
        if (ti[i]==0) b[i].t=++j;else b[i].t=n-m+ti[i];
        b[i].x=u[i];b[i].y=i;
        y[i]=b[i];
    }
    sort(b+1,b+n+1,cmp);
    sort(y+1,y+n+1,tmp);
    work0(1,n);work1(1,n);
    for (int i=2;i<=n;i++) ans[i][0]+=ans[i-1][0],ans[i][1]+=ans[i-1][1];
    for (int i=n;i>j;i--) pr(ans[i][0]+ans[i][1]);
}
View Code

 

 

 

以上是关于bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ#3295. [Cqoi2011]动态逆序对

bzoj3295: [Cqoi2011]动态逆序对

[BZOJ3295][Cqoi2011]动态逆序对

bzoj3295[Cqoi2011]动态逆序对 树套树

BZOJ3295[Cqoi2011]动态逆序对 cdq分治

bzoj3295 Cqoi2011—动态逆序对