zoukankan      html  css  js  c++  java
  • 洛谷 P1975 [国家集训队]排队

    题意:给一个序列,每次交换(a_l,a_r),并且询问交换后的整个序列的逆序对数

    分块+二分

    刚开始的逆序对数可以直接用归并排序求出来,我们先更新答案再交换,考虑每次交换的(a_l,a_r),会影响逆序对的只可能是([l,r])这个区间的数,如果单独拿出之间的一个数(a_i(l+1le ile r-1))来说,对答案则有四种可能的影响

    1. (a_i>a_l o ans++)

    (a_i)(a_l)大,(a_l)(a_r)交换之后(a_l)下标比(a_i)大,逆序对数(+1)

    1. (a_i<a_l o ans--)

    (a_i)(a_l)小,已经是逆序对,(a_l)(a_r)交换,逆序对数(-1)

    1. (a_i<a_r o ans++)

    (a_i)(a_r)小,(a_l)(a_r)交换之后(a_r)下标比(a_i)小,逆序对数(+1)

    1. (a_i>a_r o ans--)

    (a_i)(a_r)大,已经是逆序对,(a_l)(a_r)交换,逆序对数(-1)

    那么我们用分块来维护,对于在同一个块或相邻块的,暴力枚举(a_i)更新答案

    然后考虑在每个块里维护这个块的有序序列,每次访问到这个块的时候,直接二分查找更新答案,边角的数直接枚举更新就好了

    这样每次交换后对(a_l)(a_r)调整一下所在块的有序序列就好了

    注意询问的(l,r)可能(l>r)所以要交换

    蒟蒻也不会算块的大小什么的,常数还大的一批,就这样吧qwq

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <vector>
    #define N 20000
    #define rep(i,s,t) for (register int i=s;i<=t;i++)
    #define drep(i,s,t) for (register int i=s;i>=t;i--)
    using namespace std;
    int n,a[N+5],data[N+5],m,bs,blo[N+5],na[N+5],ans;
    vector <int> p[N+5];
    void merge_sort(int l,int r)
    {
        if (r-l>0)
        {
            int it=l,mid=l+r>>1,p=l,q=mid+1;
            merge_sort(l,mid);
            merge_sort(mid+1,r);
            while (p<=mid||q<=r)
            {
                if (q>r||p<=mid&&na[p]<=na[q])
                    data[it++]=na[p++];
                else
                {
                    data[it++]=na[q++];
                    ans+=mid-p+1;
                }
            }
            rep(i,l,r)
                na[i]=data[i];
        }
    }
    void com(int x,int l,int r)
    {
        ans+=a[x]>a[l];
        ans-=a[x]<a[l];
        ans+=a[x]<a[r];
        ans-=a[x]>a[r];
    }
    void reset(int x)
    {
        p[x].clear();
        rep(i,(x-1)*bs+1,x*bs)
            p[x].push_back(a[i]);
        sort(p[x].begin(),p[x].end());
    }
    void exc(int l,int r)
    {
        swap(a[l],a[r]);
        reset(blo[l]);
        reset(blo[r]);
    }
    void calc(int l,int r)
    {
        if (a[l]==a[r])
            return;
        ans+=(a[l]<a[r]);
        ans-=(a[l]>a[r]);
        if (blo[r]-blo[l]<=1)
        {
            rep(i,l+1,r-1)
                com(i,l,r);
        }
        else
        {
            rep(i,l+1,blo[l]*bs)
                com(i,l,r);
            rep(i,(blo[r]-1)*bs+1,r-1)
                com(i,l,r);
            rep(i,blo[l]+1,blo[r]-1)
            {
                ans+=p[i].end()-upper_bound(p[i].begin(),p[i].end(),a[l]);
                ans-=lower_bound(p[i].begin(),p[i].end(),a[l])-p[i].begin();
                ans+=lower_bound(p[i].begin(),p[i].end(),a[r])-p[i].begin();
                ans-=p[i].end()-upper_bound(p[i].begin(),p[i].end(),a[r]);
            }
        }
        exc(l,r);
    }
    int main()
    {
        scanf("%d",&n);
        rep(i,1,n)
            scanf("%d",&a[i]),na[i]=data[i]=a[i];
        sort(data+1,data+n+1);
        bs=sqrt(n);    
        rep(i,1,n)
        {
            blo[i]=(i-1)/bs+1;        
            na[i]=a[i]=lower_bound(data+1,data+n+1,a[i])-data;
            p[blo[i]].push_back(a[i]);
        }
        rep(i,1,blo[n])
            sort(p[i].begin(),p[i].end());
        merge_sort(1,n);
        printf("%d
    ",ans);
        scanf("%d",&m);
        int l,r;
        rep(i,1,m)
        {
            scanf("%d%d",&l,&r);
            if (l>r)
                swap(l,r);
            calc(l,r);
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    MHA-Failover(GTID,Auto_Position=0)
    PXC中的GTIDs
    MySQL备份与恢复
    MySQL复制框架
    pt-table-checksum检测不出主从差异处理
    MHA-Failover可能遇到的坑
    MHA-手动Failover流程(传统复制&GTID复制)
    MSSQL-SELECT&UPDATE动作要申请的锁
    sybench压测下模拟误truncate数据恢复
    gtid_executed和gtid_purged变量是如何初始化的
  • 原文地址:https://www.cnblogs.com/sdlang/p/13068067.html
Copyright © 2011-2022 走看看