• 洛谷 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;
    }
    
  • 相关阅读:
    topcoder srm 320 div1
    topcoder srm 325 div1
    topcoder srm 330 div1
    topcoder srm 335 div1
    topcoder srm 340 div1
    topcoder srm 300 div1
    topcoder srm 305 div1
    topcoder srm 310 div1
    topcoder srm 315 div1
    如何统计iOS产品不同渠道的下载量?
  • 原文地址:https://www.cnblogs.com/sdlang/p/13068067.html
Copyright © 2020-2023  润新知