• bzoj3295动态逆序对


    Cqoi2011]动态逆序对

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 5362  Solved: 1814
    [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)。
    这道题就是求每个值插进去后会形成多少个逆序对,前提是另外一个数的出现时间比这个数小。这样可以保证逆序对数不会重复,也不会漏算。
    CDQ分治吧,动态树LCT我不会。
    抽离出模型,就是求(i,j)|(ti<tj,xi<xj,vali>valj)和(ti<tj,xi>xj,vali<valj)个数
    外层按t值排序,然后将区间(l,r)分成(l,mid)和(mid+1,r);(l,mid)中的t肯定比(mid+1,r)中的小。
    然后用个辅助数组中按x排序,考虑对右半部分的贡献,(这是CDQ分治的精髓)利用树状数组的方法求出答案。
    其实写的慢出翔,不用辅助数组或者按归并排序对t排序都会快的多
    T(n)=2T(n/2)+nlogn的时间复杂度是nlognlogn,用归并可以去掉1个logn吧
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define maxn 100011
    struct note{
        int x,y,t;
        int flag;
    }a[maxn],b[maxn];
    int n,m,c[maxn],pos[maxn],ans[maxn];
    #define lowbit(x) x&-x
    inline bool cmpx(note q,note qq)
    {
        if(q.x==qq.x){return q.y<qq.y;}
        return q.x<qq.x;
    }
    inline bool cmpt(note q,note qq){ return q.t<qq.t; }
    void add(int u,int v){for(int j=u;j<=n;c[j]+=v,j+=lowbit(j));}
    int query(int u){int sum=0;for(int j=u;j;sum+=c[j],j-=lowbit(j));return sum;}
    
    void CDQ(int l,int r)
    {
        if(l>=r)return;
        int mid=(l+r)>>1,size=r-l+1,cnt=0;
        for(int i=l;i<=mid;i++)b[++cnt]=a[i],b[cnt].flag=0;for(int i=mid+1;i<=r;i++) b[++cnt]=a[i],b[cnt].flag=1;
        sort(b+1,b+1+cnt,cmpx);
        for(int i=1;i<=size;i++)
        if(!b[i].flag) add(b[i].y,1);
        else ans[b[i].t]+=query(n)-query(b[i].y);
        for(int i=1;i<=size;i++)
            if(!b[i].flag)add(b[i].y,-1);
         for(int i=size;i>=1;i--)
             if(!b[i].flag)add(b[i].y,1);else ans[b[i].t]+=query(b[i].y);
        for(int i=size;i>=1;i--)
            if(!b[i].flag)add(b[i].y,-1);
         CDQ(l,mid);if(mid<r) CDQ(mid+1,r); 
    }
    void debug()
    {
        for(int i=1;i<=n;i++)
        cout<<a[i].x<<' '<<a[i].y<<' '<<a[i].t<<endl;
    }
    int main()
    {
        scanf("%d %d",&n,&m);
        int Timerec=n;
        for(int i=1;i<=n;i++){int x;scanf("%d",&x);a[i].x=i,a[i].y=x;pos[x]=i;}
        for(int i=1;i<=m;i++){int x;scanf("%d",&x);a[pos[x]].t=Timerec--;} 
        //debug();
        for(int i=1;i<=n;i++)if(!a[i].t){a[i].t=Timerec--;} 
        sort(a+1,a+1+n,cmpt);CDQ(1,n);
        long long Ans=0;
        for(int i=1;i<=n;i++) Ans+=ans[i];
        for(int i=n;i>n-m;i--)
        {
            printf("%lld
    ",Ans);
            Ans-=ans[i]; 
        }
        
    }

    http://www.hekai.site/wordpress/2017/08/26/cdq%E5%88%86%E6%B2%BB%E8%AF%A6%E8%A7%A3%EF%BC%88bzoj3262-%E9%99%8C%E4%B8%8A%E8%8A%B1%E5%BC%80%EF%BC%89/

    HKdalao的题解,题目不一样,但思路差不多吧

     
  • 相关阅读:
    haproxy的使用
    zookeeper 的多线程和单线程库使用对比
    zookeeper 简介
    将博客搬至CSDN
    Sublime Text 添加eclipse快捷键
    Atom编辑器添加eclipse快捷键
    Linux安装mysql教程
    设计模式
    设计模式
    设计模式
  • 原文地址:https://www.cnblogs.com/dancer16/p/7455797.html
Copyright © 2020-2023  润新知