zoukankan      html  css  js  c++  java
  • [Ynoi2019模拟赛]Yuno loves sqrt technology I

    题目描述

    给你一个长为n的排列,m次询问,每次查询一个区间的逆序对数,强制在线。

    题解

    MD不卡了。。TMD一点都卡不动。

    强制在线的话也没啥好一点的方法,只能分块预处理了。

    对于每个块,我们设lef[i]表示i到这个i这个元素所在块的块头的区间逆序对,rig[i]表示到块尾的逆序对。

    在设一个cnt[i][j]表示从第i个块到第j个块的逆序对。

    然后考虑如何处理询问。

    整块之间的可以直接O(1)取答案,对于散块,我们需要求出散块内部的答案,散块对整块的答案,散块对散块的答案。

    对于散块内的,因为散块在当前块中一定是它的前缀或后缀,所以我们直接O(1)取答案。

    对于散块对整块的,我们可以在维护一个tag[i][j]表示前i个块,大于/小于j的元素有多少个,然后询问就扫描散块,前缀和统计即可。

    对于散块对散块的,可以在每个块内维护元素的相对大小,然后对于两个不相交的区间,可以用桶排+扫描求出逆序对。

    但还有一个特殊情况,就是lr在同一个块里,前面的方法不是很实用。

    我们设当前块头尾h,那么答案可以表示为ans(h-r)-ans(h-l)-ans(h~l,l~r),前两个部分已经求过了,后面的用桶排+扫描即可。

    不过常数略大,开2s应该能过。

    代码

    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #pragma GCC optimize ("Ofast")
    #pragma GCC optimize ("Ofast","inline","unroll-loops")
    #pragma GCC optimize ("no-stack-protector")
    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cassert>
    #include <cmath>
    #define N 100002
    #define M 340
    using namespace std;
    typedef long long ll;
    int n,m,tr[N],mis[M],rnk[N],n1,ji[M],be[N],a[N],b[M],lef[N],tag1[M][N],tag2[M][N],rig[N],tong[N];
    int q[N],pos[N];
    ll ans,cnt[M][M];
    inline void add(int x,int y){while(x<=n)tr[x]+=y,x+=x&-x;}
    inline int query(int x){int ans=0;while(x)ans+=tr[x],x-=x&-x;return ans;}
    inline int merge(int l2,int r2,int l1,int r1){
        int ans=0;
        for(int i=l1;i<=r1;++i)ji[rnk[i]]=a[i];
        q[0]=0;
        for(int i=1;i<=n1;++i)if(ji[i]){
          q[++q[0]]=ji[i];ji[i]=0;
        }
        int p=0;
        for(int i=l2;i<=r2;++i)ji[rnk[i]]=a[i];
        for(int i=1;i<=n1;++i)if(ji[i]){
            while(p<=q[0]&&(!p||q[p]<=ji[i]))p++;p--;
            ans+=p;ji[i]=0;
        }
        return ans;
    }
    inline int rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }
    int main(){
        n=rd();m=rd();
        n1=320;
        for(int i=1;i<=n;++i)a[i]=rd(),be[i]=(i-1)/n1+1,pos[a[i]]=i;
        for(int i=1;i<=be[n];++i){      
            int l=(i-1)*n1+1,r=min(n,i*n1);int top=0;
            for(int j=l;j<=r;++j)b[++top]=a[j];
            sort(b+1,b+top+1);
            for(int j=1;j<=top;++j)rnk[pos[b[j]]]=j;
            for(int j=l;j<=r;++j){
                lef[j]=query(n-a[j]+1);
                if(j!=l)lef[j]+=lef[j-1];
                add(n-a[j]+1,1);tong[n-a[j]+1]=1;
            }
            int moss=0;
            for(int j=n;j>=1;--j){
              moss+=tong[n-j+1];
              tag2[i][j]=tag2[i-1][j]+moss;
            }
            for(int j=l;j<=r;++j)add(n-a[j]+1,-1),tong[n-a[j]+1]=0;
            for(int j=r;j>=l;--j){
                rig[j]=query(a[j]);
                if(j!=r)rig[j]+=rig[j+1];
                add(a[j],1);tong[a[j]]=1;
            }
            moss=0;
            for(int j=1;j<=n;++j){
              moss+=tong[j];
              tag1[i][j]=tag1[i-1][j]+moss;
            }
            for(int j=l;j<=r;++j)add(a[j],-1),tong[a[j]]=0;
        }
        for(int i=1;i<=be[n];++i){
            cnt[i][i]=lef[min(n,i*n1)];
            for(int j=i+1;j<=be[n];++j){
                cnt[i][j]=cnt[i][j-1];int x=min(n,n1*j);
                for(int k=(j-1)*n1+1;k<=x;++k){
                    cnt[i][j]+=tag2[j-1][a[k]]-tag2[i-1][a[k]];
                }
                cnt[i][j]+=lef[x];
            }
        }
        int l,r;
        while(m--){
            l=rd();r=rd();l^=ans;r^=ans;
            if(l>r)l^=r^=l^=r;ans=0;
          //  if(r>n||l<1){ans=0;puts("0");continue;}
            if(be[l]==be[r]){
                  ans=lef[r];if(l!=(be[l]-1)*n1+1)ans-=lef[l-1],ans-=merge((be[l]-1)*n1+1,l-1,l,r); 
            }
            else{
                int st=be[l]+1,en=be[r]-1;
               for(int i=l;i<=be[l]*n1;++i)ans=ans+tag1[en][a[i]]-tag1[st-1][a[i]];
               for(int i=en*n1+1;i<=r;++i)ans=ans+tag2[en][a[i]]-tag2[st-1][a[i]];
               ans+=cnt[st][en]+rig[l]+lef[r];
               ans+=merge(l,(st-1)*n1,en*n1+1,r);
            }
             printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (二) —— SQLite
    理解 Continuation
    99种用Racket说I love you的方式
    Racket Cheat Sheet
    scheme 教程 #lang racket
    开始学习Scheme
    MIT Scheme 的基本使用
    CPS变换
    SECD machine
    scheme 之门
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10449396.html
Copyright © 2011-2022 走看看