bzoj3295[Cqoi2011]动态逆序对(cdq分治||可持久化线段树)

来源:互联网 发布:数据报表图片 编辑:程序博客网 时间:2024/06/05 16:25

题目链接:点这里!!!


3295: [Cqoi2011]动态逆序对

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 3043  Solved: 967
[Submit][Status][Discuss]

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



做法1:cdq分治

1、首先我们看到求逆序对,很容易想到用树状数组去求逆序对,这里在有修改的情况下,我们一样用树状数组来做,只是再加上cdq分治。


2、首先我们倒过来做,把删除看成添加操作。比如例题:它的添加顺序是(数值):3(没有被删除的数先添加)、2、4、1、5。


3、然后我们来定义一个数组a,三个属性id(添加操作的顺序),val(数值的大小),pv(在序列里的位置)。


4、按照id来排序。 然后我们对val来分治,用pv来更新和求值。


5、注意要更新两次和求值两次,具体看代码,再叠加起来就可。


代码:

#include<cstdio>#include<cstring>#include<iostream>#include<sstream>#include<algorithm>#include<vector>#include<bitset>#include<set>#include<queue>#include<stack>#include<map>#include<cstdlib>#include<cmath>#define PI 2*asin(1.0)#define LL long long#define pb push_back#define pa pair<int,int>#define clr(a,b) memset(a,b,sizeof(a))#define lson lr<<1,l,mid#define rson lr<<1|1,mid+1,r#define bug(x) printf("%d++++++++++++++++++++%d\n",x,x)#define key_value ch[ch[root][1]][0]C:\Program Files\Git\binconst int  MOD = 1E9+7;const LL N = 1E5+15;const int maxn = 1e4+1000;const int letter = 130;const int INF = 1e17;const double pi=acos(-1.0);const double eps=1e-8;using namespace std;inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int n,k,val[N],c[N],vis[N],pp[N];LL ans[N];vector<int>ps;struct node{    int id,val,pv;}a[N],b[N];bool cmp(node a,node b){    return a.id<b.id;}int lowbit(int x){return x&(-x);}void update(int i,int v){    for(int x=i;x<=n;x+=lowbit(x)) pp[x]+=v;}int getsum(int i){    int ans=0;    for(int x=i;x;x-=lowbit(x)) ans+=pp[x];    return ans;}void solve(int l,int r){    if(l==r) return;    int mid=(l+r)>>1;/// val    for(int i=l;i<=r;i++){        if(a[i].val<=mid) update(a[i].pv,1);        else ans[a[i].id]+=1ll*(getsum(n)-getsum(a[i].pv));    }    for(int i=l;i<=r;i++) if(a[i].val<=mid) update(a[i].pv,-1);    for(int i=l;i<=r;i++){        if(a[i].val>mid) update(a[i].pv,1);        else ans[a[i].id]+=1ll*getsum(a[i].pv-1);    }    for(int i=l;i<=r;i++) if(a[i].val>mid) update(a[i].pv,-1);    int ll=l;    for(int i=l;i<=r;i++) if(a[i].val<=mid) b[ll++]=a[i];    for(int i=l;i<=r;i++) if(a[i].val>mid) b[ll++]=a[i];    for(int i=l;i<=r;i++) a[i]=b[i];    solve(l,mid);    solve(mid+1,r);}int main(){    ps.clear();    int x;    n=read(),k=read();    for(int i=1;i<=n;i++){        a[i].val=read(),a[i].pv=i;        c[a[i].val]=i;    }    for(int i=1;i<=k;i++){        x=read();        vis[c[x]]=1;        ps.pb(c[x]);    }    int cnt=0;    for(int i=1;i<=n;i++){        if(!vis[i]) a[i].id=++cnt;    }    for(int i=ps.size()-1;i>=0;i--) a[ps[i]].id=++cnt;    sort(a+1,a+cnt+1,cmp);    solve(1,n);    for(int i=1;i<=n;i++){        ans[i]+=ans[i-1];    }    for(int i=k;i>=1;i--){        printf("%lld\n",ans[n-k+i]);    }    return 0;}/*5 41 5 3 4 25 1 4 25 55 4 3 2 15 4 3 2 1*/

做法2:可持久化线段树


这道题做了一天,超了一天的内存,傻逼了。= =,然后优化一下就过了,一脸蒙逼。


1、注意一下数据范围:n<=100000 m<=50000。一开始做的时候我用的是n个数去维护可持久化线段树,各种超内存。


2、仔细想了一下我们有n-m个数没有变过,所以我们离线处理。其他m个点,插入用可持久化线段树即可。


#include<cstdio>#include<cstring>#include<iostream>#include<sstream>#include<algorithm>#include<vector>#include<bitset>#include<set>#include<queue>#include<stack>#include<map>#include<cstdlib>#include<cmath>#define PI 2*asin(1.0)#define LL long long#define pb push_back#define pa pair<int,int>#define clr(a,b) memset(a,b,sizeof(a))#define lson lr<<1,l,mid#define rson lr<<1|1,mid+1,r#define bug(x) printf("%d++++++++++++++++++++%d\n",x,x)#define key_value ch[ch[root][1]][0]C:\Program Files\Git\binconst int  MOD = 1E9+7;const LL N = 1E5+15;const int maxn = 1e4+1000;const int letter = 130;const int INF = 1e17;const double pi=acos(-1.0);const double eps=1e-8;using namespace std;inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int n,k,val[N],w[N],c[N],d[N];int sum[N*100],ls[N*100],rs[N*100],root[N],siz,ps[N],vis[N];int pl[50],pr[50],aa,bb;int vl[N],vr[N];vector<LL>pp;int lowbit(int x){    return x&(-x);}void update(int i,int val){    for(int x=i;x<=n;x+=lowbit(x)) ps[x]+=val;}int getsum(int i){    int ans=0;    for(int x=i;x>0;x-=lowbit(x)) ans+=ps[x];    return ans;}void insert(int ll,int rr,int x,int &y,int v,int add){    y=++siz;    sum[y]=sum[x]+add;    ls[y]=ls[x],rs[y]=rs[x];    if(ll==rr) return;    int mid=(ll+rr)>>1;    if(v<=mid) insert(ll,mid,ls[x],ls[y],v,add);    else insert(mid+1,rr,rs[x],rs[y],v,add);}int query(int l,int r,int w){ ///1 n w    int suml=0,sumr=0;    if(l==r){        for(int i=0;i<aa;i++) suml+=sum[pl[i]];        for(int i=0;i<bb;i++) sumr+=sum[pr[i]];        return sumr-suml;    }    int mid=(l+r)>>1;    for(int i=0;i<aa;i++) suml+=sum[ls[pl[i]]];    for(int i=0;i<bb;i++) sumr+=sum[ls[pr[i]]];    if(w<=mid){        for(int i=0;i<aa;i++) pl[i]=ls[pl[i]];        for(int i=0;i<bb;i++) pr[i]=ls[pr[i]];        return query(l,mid,w);    }    else {        for(int i=0;i<aa;i++) pl[i]=rs[pl[i]];        for(int i=0;i<bb;i++) pr[i]=rs[pr[i]];        return sumr-suml+query(mid+1,r,w);    }}void init(){    pp.clear();    scanf("%d%d",&n,&k);    for(int i=1;i<=n;i++){        val[i]=read();        w[val[i]]=i; ///at    }    for(int i=1;i<=k;i++){        int x;        x=read();        d[i]=x;        c[i]=w[x];        vis[c[i]]=1;    }    LL ans=0;    int cnt=0;    for(int i=1;i<=n;i++){        if(!vis[i]){ ///no            update(val[i],1);            ans+=1ll*(cnt-getsum(val[i]-1));            cnt++;        }        else {  /// shanchu            vl[i]=cnt-getsum(val[i]-1);        }    }    cnt=0;    clr(ps,0);    for(int i=n;i>=1;i--){        if(!vis[i]){            update(val[i],1);        }        else {            vr[i]=getsum(val[i]-1);        }    }    clr(ps,0);    for(int i=k;i>=1;i--){        aa=bb=0;        for(int j=c[i];j<=n;j+=lowbit(j)) insert(1,n,root[j],root[j],d[i],1);        for(int j=c[i]-1;j;j-=lowbit(j)) pr[bb++]=root[j];        update(c[i],1);        ans+=1ll*((LL)getsum(c[i]-1)-(LL)query(1,n,d[i]-1)+vl[c[i]]);        aa=bb=0;        for(int j=c[i];j;j-=lowbit(j)) pl[aa++]=root[j];        for(int j=n;j;j-=lowbit(j)) pr[bb++]=root[j];        ans+=1ll*(vr[c[i]]+query(1,n,d[i]-1));        pp.pb(ans);    }    for(int i=pp.size()-1;i>=0;i--) printf("%lld\n",pp[i]);}int main(){   // freopen("input.txt","r",stdin);   // freopen("out.txt","w",stdout);    init();    return 0;}/*5 41 5 3 4 25 1 4 210 510 9 8 7 6 5 4 3 2 15 4 3 2 15 35 4 3 2 13 2 1*/


0 0
原创粉丝点击