3295: [Cqoi2011]动态逆序对 CDQ分治

来源:互联网 发布:手机淘宝海报在线制作 编辑:程序博客网 时间:2024/05/21 16:22

依稀记得400题的时候就是做的这道题,写的树套树结果电脑死机了就没重新写。
由于此题可以离线,把删除操作改为逆序插入操作。
我们看一下样例,可以得到这样三个序列。
n:1 2 3 4 5
x:3 5 4 1 2
y:3 2 4 1 5
其中n为插入的顺序(就是删除的逆序),x为这个值在原序列中的位置,y为按顺序添加的数(不足补齐)。
然后考虑产生逆序对的情况:如果当前加入的数,之前已经加入一个比它小的数,且这个数的位置在它的后面,形式的说就是同时满足:ni<nj,xi>xj,yi<yj。而如果当前加入的数,之前已经加入一个比它大的数,且这个数的位置在它的前面,形式的说就是同时满足ni<nj,xi<xj,yi>yj,可以发现这两个问题是类似的,我们可以通过令xi=nxi+1或令yi=nyi+1转化为三维偏序的问题,然后就用CDQ分治解决就好了。
统计答案维护答案的前缀和。

#include<iostream>#include<cstdio>#include<algorithm>#define lowbit(i) (i&(-i))#define ll long long #define N 100005using namespace std;int n,m;int x[N],u[N],w[N],pos[N],tree[N];ll ans[N];struct node {int x,y,z; ll ans;} a[N],b[N];inline int read() {    int a=0,f=1; char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}    return a*f;}inline void add(int x,int val){    for (int i=x;i<=n;i+=lowbit(i)) tree[i]+=val;}inline int query(int x){    int tmp=0;    for (int i=x;i;i-=lowbit(i)) tmp+=tree[i];    return tmp;}void solve(int l,int r){    if (l==r) return;    int mid=l+r>>1,p1=l,p2=mid+1;    solve(l,mid); solve(mid+1,r);    while (p2<=r)    {        while (p1<=mid&&a[p1].y<a[p2].y)         {            add(a[p1].z,1);            p1++;        }        a[p2].ans+=query(a[p2].z);        p2++;    }    for (int i=l;i<p1;i++) add(a[i].z,-1);    p1=l; p2=mid+1;    for (int i=l;i<=r;i++)        if (p1<=mid&&(p2>r||a[p1].y<a[p2].y)) b[i]=a[p1++]; else b[i]=a[p2++];    for (int i=l;i<=r;i++) a[i]=b[i];}       int main(){    n=read(); m=read();    for (int i=1;i<=n;i++) w[read()]=i;    for (int i=1;i<=m;i++) x[i]=read(),u[x[i]]=1;    for (int i=1,k=m;i<=n;i++) if(!u[i]) x[++k]=i;    for (int i=n;i;i--) a[n-i+1]=(node){n-i+1,n-w[x[i]]+1,x[i]};    solve(1,n);    for (int i=1;i<=n;i++) ans[a[i].x]+=a[i].ans;    for (int i=n;i;i--) a[n-i+1]=(node){n-i+1,w[x[i]],n-x[i]+1};    solve(1,n);    for (int i=1;i<=n;i++) ans[a[i].x]+=a[i].ans;    for (int i=1;i<=n;i++) ans[i]+=ans[i-1];    for (int i=n;i>n-m;i--) printf("%lld\n",ans[i]);    return 0;}
0 0
原创粉丝点击