[bzoj3295][Cqoi2011]动态逆序对

来自FallDream的博客,未经允许,请勿转载,谢谢。


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

n<=100000 m<=50000

呃我感觉我中毒了 看到这道题第一个想法就是对询问分块

建出主席树,然后把操作压到栈里面,然后每次查询都遍历这个栈,计算答案。然后当操作达到一定数量的时候重建主席树。

块的大小取大约$sqrt{nlogn}$比较优秀 复杂度$O(m(k+logn)+frac{n}{k}nlogn)$

当然更靠谱的做法是cdq分治,这道题其实就是一道三维偏序 先对时间排序,然后在分治的时候对x排序,用树状数组/线段树处理y维即可。

复杂度$O(nlog^{2}n)$

询问分块

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define mp(x,y) make_pair(x,y)
#define MN 100000
#define ll long long
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;
}
ll ans=0,Ans[MN+5];
int n,m,sz,rt[MN+5],cnt=0,s[MN+5],qx[MN+5],pos[MN+5],q[MN+5],top=0;
bool b[MN+5];
struct Tree{int l,r,x;}T[MN*20];

void ins(int x,int nx,int k)
{
    int l=1,r=n,mid;T[nx].x=T[x].x+1;
    while(l<r)
    {
        mid=l+r>>1;
        if(k<=mid) T[nx].r=T[x].r,T[nx].l=++cnt,r=mid,x=T[x].l,nx=T[nx].l;
        else T[nx].l=T[x].l,T[nx].r=++cnt,l=mid+1,x=T[x].r,nx=T[nx].r;
        T[nx].x=T[x].x+1;
    }
}

int query(int x,int nx,int k)
{
    int l=1,r=n,mid,sum=0;
    while(l<r)
    {
        mid=l+r>>1;
        if(k<=mid) x=T[x].l,nx=T[nx].l,r=mid;
        else sum+=(T[T[nx].l].x-T[T[x].l].x),x=T[x].r,nx=T[nx].r,l=mid+1; 
    }
    return sum+T[nx].x-T[x].x;
}

void build()
{
    cnt=0;
    for(int i=1;i<=n;i++) 
        b[i]?rt[i]=rt[i-1]:(ins(rt[i-1],rt[i]=++cnt,s[i]),0);
}

int main()
{
    n=read();m=read();sz=sqrt(n*15);
    for(int i=1;i<=n;i++) pos[s[i]=read()]=i;
    for(int i=1;i<=m;i++) q[i]=read(),b[pos[q[i]]]=1;
    build();
    for(int i=2;i<=n;i++) if(!b[i])
        ans+=T[rt[i-1]].x-query(0,rt[i-1],s[i]);
    for(int i=m;i;i--)
    {
        if(pos[q[i]]!=1) ans+=T[rt[pos[q[i]]-1]].x-query(0,rt[pos[q[i]]-1],q[i]);
        if(pos[q[i]]!=n) ans+=query(rt[pos[q[i]]],rt[n],q[i]);
        for(int j=1;j<=top;j++)
            if((qx[j]>q[i]&&pos[qx[j]]<pos[q[i]])||(qx[j]<q[i]&&pos[qx[j]]>pos[q[i]])) ++ans;
        Ans[i]=ans;b[pos[q[i]]]=0;
        qx[++top]=q[i];
        if(top>=sz) build(),top=0;
    }
    for(int i=1;i<=m;i++) printf("%lld
",Ans[i]);
    return 0;
}
View Code

cdq分治

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
#define MN 100000
#define N 131072
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,m,T[N*2+5],ans=0,s[MN+5];ll Ans[MN+5],pos[MN+5];
struct ques{int kind,t,x,y;}q[MN+5],b[MN+5];

int query(int l,int r)
{
    int sum=0;
    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1) sum+=T[l+1];
        if( r&1) sum+=T[r-1];
    }
    return sum;
}

void renew(int x,int ad)
{
    T[x+=N]+=ad;
    for(x>>=1;x;x>>=1)T[x]=T[x<<1]+T[x<<1|1];
}
bool cmpX(ques x,ques y){return x.x<y.x;}
void solve(int l,int r)
{
    if(l>=r) return;
    int mid=l+r>>1;
    for(int i=l;i<=r;i++) b[i]=q[i],b[i].kind=(i<=mid)?1:2;
    sort(b+l,b+r+1,cmpX);
    for(int i=l;i<=r;i++) 
        if(b[i].kind==1) renew(b[i].y,1);
        else Ans[b[i].t]+=query(b[i].y,n);
    for(int i=l;i<=r;i++) 
        if(b[i].kind==1)renew(b[i].y,-1);
    for(int i=r;i>=l;i--) 
        if(b[i].kind==1)renew(b[i].y,1);
        else Ans[b[i].t]+=query(1,b[i].y);
    for(int i=l;i<=r;i++) 
        if(b[i].kind==1)renew(b[i].y,-1);  
    solve(l,mid);
    solve(mid+1,r);
}
bool cmpT(ques x,ques y){return x.t<y.t;}
int main()
{
    n=read();m=read();int tot=n;
    for(int i=1;i<=n;i++)pos[s[i]=read()]=i; 
    for(int i=1;i<=m;i++)q[pos[read()]].t=tot--;
    for(int i=1;i<=n;q[i].x=i,q[i].y=s[i],++i)if(!q[i].t) q[i].t=tot--;
    sort(q+1,q+n+1,cmpT);
    solve(1,n);ll sum=0;
    for(int i=1;i<=n;i++) sum+=Ans[i];
    for(int i=n;i>n-m;i--) printf("%lld
",sum),sum-=Ans[i];
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/FallDream/p/bzoj3295.html