zoukankan      html  css  js  c++  java
  • bzoj3295 [Cqoi2011]动态逆序对

    3295: [Cqoi2011]动态逆序对

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 6119  Solved: 2142
    [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

    分析:cdq分治比较裸的题目.考虑i,j如何才能构成逆序对:Ti < Tj,Xi < Xj,Yi > Yj.其中T是cdq分治中的时间,X是下标,Y是大小.因为题目只涉及到删除操作,那么可以用一个很常用的方法:时间倒流来处理.每增加一个点,看T ≤ mid的点中有多少x比它大并且y比它小的点,和x比它小并且y比它大的点.因为每次不光是要计算原先被删除的点构成的逆序对,还要算序列中剩下的数的逆序对.那么一开始将序列初始化为空序列,对每一个元素分配一个T,代表插入的时间,其中没有被删除的点要先分配,这样就能做到统计答案不遗漏了.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    const int maxn = 100010;
    int n,m,pos[maxn],T;
    ll ans[maxn],c[maxn],Ans;
    
    struct node
    {
        int id,x,y;
    }e[maxn],p[maxn];
    
    bool cmp(node a,node b)
    {
        if (a.x == b.x && a.y == b.y)
            return a.id < b.id;
        if (a.x == b.x)
            return a.y < b.y;
        return a.x < b.x;
    }
    
    void add(int x,int v)
    {
        while (x <= n)
        {
            c[x] += v;
            x += x & (-x);
        }
    }
    
    ll query(int x)
    {
        ll res = 0;
        while (x)
        {
            res += c[x];
            x -= x & (-x);
        }
        return res;
    }
    
    void solve(int l,int r)
    {
        if (l == r)
            return;
        int mid = (l + r) >> 1;
        for (int i = l; i <= r; i++)
            {
                if (e[i].id <= mid)
                    add(e[i].y,1);
                else
                    ans[e[i].id] += query(n) - query(e[i].y);
            }
        for (int i = l; i <= r; i++)
            if (e[i].id <= mid)
                add(e[i].y,-1);
        for (int i = r; i >= l; i--)
        {
            if (e[i].id <= mid)
                add(e[i].y,1);
            else
                ans[e[i].id] += query(e[i].y);
        }
        for (int i = r; i >= l; i--)
            if (e[i].id <= mid)
                add(e[i].y,-1);
        int L = l,R = mid + 1;
        for (int i = l; i <= r; i++)
        {
            if (e[i].id <= mid)
                p[L++] = e[i];
            else
                p[R++] = e[i];
        }
        for (int i = l; i <= r; i++)
            e[i] = p[i];
        solve(l,mid);
        solve(mid + 1,r);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        T = n;
        for (int i = 1; i <= n; i++)
        {
            scanf("%d",&e[i].y);
            e[i].x = i;
            pos[e[i].y] = i;
        }
        for (int i = 1; i <= m; i++)
        {
            int k;
            scanf("%d",&k);
            e[pos[k]].id = T--;
        }
        for (int i = 1; i <= n; i++)
            if (!e[i].id)
                e[i].id = T--;
        sort(e + 1,e + 1 + n,cmp);
        solve(1,n);
        for (int i = 1; i <= n; i++)
            Ans += ans[i];
        for (int i = n; i > n - m; i--)
        {
            printf("%lld
    ",Ans);
            Ans -= ans[i];
        }
    
        return 0;
    }
  • 相关阅读:
    KindEditor自动过滤首行缩进和全角空格的解决方法
    网站流量、连接数等监控
    VSFTP的使用
    CentOs 设置静态IP
    MySQL 5.7版本sql_mode=only_full_group_by问题
    使用密钥登录CentOS系统(基于密钥的认证)
    FIRMWARE BUG – THE BIOS HAS CORRUPTED HW-PMU RESOURCES
    Ubuntu上的MySQL可以远程访问
    自动生成单据编号
    SQL Server 重置SA密码语句
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8213868.html
Copyright © 2011-2022 走看看