zoukankan      html  css  js  c++  java
  • Codeforces785E

    Portal

    Description

    对一个长度为(n(nleq2 imes10^5))的数列(a)进行(m(mleq5 imes10^4))次操作,数列初始时为({1,2,...,n})。每次操作交换数列中的两个数(a_L)(a_R),并询问此时数列(a)中的逆序对数。

    Solution

    交换(a_L)(a_R)时,会影响逆序对数的只有下标在((L,R))之间,数值在(a_L)(a_R)之间的数(钦定(L<R))。设这样的数有(k)个,那么若(a_L<a_R),逆序对数会增加(2k+1);若(a_L>a_R),逆序对数会减少(2k+1)
    所以只要使用一种数据结构,支持单点修改和查询区间内数值在某个范围内的数的个数。分块即可解决这个问题。维护每个块内的数有序,那么就可以通过二分查找以(O(logsqrt n))求出块内满足条件的数的个数。对于修改,修改之后将所在块再次排序即可。

    时间复杂度(O(msqrt nlogsqrt n)。)

    Code

    //Anton and Permutation
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    typedef long long lint;
    inline char gc()
    {
        static char now[1<<16],*S,*T;
        if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;}
        return *S++;
    }
    inline int read()
    {
        int x=0; char ch=gc();
        while(ch<'0'||'9'<ch) ch=gc();
        while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
        return x;
    }
    int const N=2e5+1e3;
    int n,m,n0,a[N];
    int blk[N],fr[N],to[N],b[N];
    int query(int t,int x,int y)
    {
        int L=upper_bound(b+fr[t],b+to[t]+1,x)-b;
        int R=lower_bound(b+fr[t],b+to[t]+1,y)-b-1;
        return R-L+1;
    }
    void update(int t)
    {
        for(int i=fr[t];i<=to[t];i++) b[i]=a[i];
        sort(b+fr[t],b+to[t]+1);
    }
    int main()
    {
        n=read(),m=read(); n0=sqrt(n);
        for(int i=1;i<=n;i++) a[i]=b[i]=i;
        for(int i=1;i<=n;i++) blk[i]=(i-1)/n0+1;
        for(int i=1;i<=blk[n];i++) fr[i]=(i-1)*n0+1,to[i]=i*n0;
        to[blk[n]]=n;
        lint ans=0;
        for(int i=1;i<=m;i++)
        {
            int L=read(),R=read(); if(L>R) swap(L,R);
            if(L==R) {printf("%lld
    ",ans); continue;}
            int x=a[L],y=a[R]; lint res=0,f=1;
            if(x>y) swap(x,y),f=-1;
            if(blk[L]==blk[R]) for(int i=L;i<=R;i++) res+=(x<a[i]&&a[i]<y);
            else
            {
                for(int i=L;i<=to[blk[L]];i++) res+=(x<a[i]&&a[i]<y);
                for(int t=blk[L]+1;t<=blk[R]-1;t++) res+=query(t,x,y);
                for(int i=fr[blk[R]];i<=R;i++) res+=(x<a[i]&&a[i]<y);
            }
            ans+=2*res*f; if(a[L]<a[R]) ans++; else ans--;
            swap(a[L],a[R]); update(blk[L]),update(blk[R]);
            printf("%lld
    ",ans);
        }
        return 0;
    }
    

    P.S.

    要用long long来保存逆序对数。
    存在(L=R)的情况,可以特判一下。

  • 相关阅读:
    中小企业服务器配置方案(第三章 Web服务器)
    判断中日韩文的正则表达式
    中小企业服务器配置方案(第一章 代理接入服务器)
    ThinkPHP怎么样更好的使用Smarty第三方插件
    thinkphp 的目录结构
    学习Mysql命令行
    中小企业服务器配置方案(第五章 文件服务器)
    正则字符对应说明
    mysql导入导出.sql文件备份还原数据库[mysql导入导出sql命令行]
    中小企业服务器配置方案(第四章 邮件服务器)
  • 原文地址:https://www.cnblogs.com/VisJiao/p/8491372.html
Copyright © 2011-2022 走看看