您的位置:首页 > 其它

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

2016-03-01 11:21 423 查看
依稀记得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<yjn_ix_j,y_i。而如果当前加入的数,之前已经加入一个比它大的数,且这个数的位置在它的前面,形式的说就是同时满足ni<nj,xi<xj,yi>yjn_iy_j,可以发现这两个问题是类似的,我们可以通过令xi=n−xi+1x_i=n-x_i+1或令yi=n−yi+1y_i=n-y_i+1转化为三维偏序的问题,然后就用CDQ分治解决就好了。

统计答案维护答案的前缀和。

[code]#include<iostream>
#include<cstdio>
#include<algorithm>
#define lowbit(i) (i&(-i))
#define ll long long 
#define N 100005
using namespace std;
int n,m;
int x
,u
,w
,pos
,tree
;
ll ans
;
struct node {int x,y,z; ll ans;} a
,b
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: