[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应该能过(用了CAT的IO优化都不行。。)

代码

#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 RG register
#define set_file(FinlineE) freopen(FinlineE ".in", "r", stdin), freopen(FinlineE ".out", "w", stdout)
#define close_file() fclose(stdin), fclose(stdout)
#define For(i, a, b) for(RG int i = a, ___u = b; i <= ___u; ++i)
#define ForDown(i, a, b) for(RG int i = b, ___d = a; i >= ___d; --i)
#define cmax(i, j) ((i) < (j) ? (i) = (j) : (i))
#define cmin(i, j) ((i) > (j) ? (i) = (j) : (i))
#define dmax(i, j) ((j) < (i) ? (i) : (j))
#define dmin(i, j) ((i) < (j) ? (i) : (j))
#define ddel(i, j) ((i) > (j) ? (i) - (j) : (j) - (i))
#define dabs(i) ((i) > 0 ? (i) : -(i))
#define dsqr(x) ((x) * (x))
#define lowbit(i) ((i) & -(i))
using namespace std;
#define N 100002
#define M 340
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];
int q[N],pos[N];
ll ans,cnt[M][M];
namespace io
{
    const int MAXBUF = 1 << 20;
    const int OUTPUT = 1 << 23;
    char B[MAXBUF], *S = B, *T = B;
    #define getc() (S == T && (T = (S = B) + fread(B, 1, MAXBUF, stdin), S == T) ? 0 : *S++)
    #define fastcall __attribute__((optimize("-O3")))
    #define inline __inline__ __attribute__((always_inline))
    template<class Type> inline Type read()
    {
        RG Type aa = 0; RG bool bb = 0; RG char ch, *S = io::S, *T = io::T;
        for(ch = getc(); (ch < '0' || ch > '9') && ch != '-'; ch = getc())
            ;
        for(ch == '-' ? bb = 1 : aa = ch - '0', ch = getc(); '0' <= ch && ch <= '9'; ch = getc())
            aa += (aa << 3) + aa + ch - '0';
        io::S = S, io::T = T; return bb ? -aa : aa;
    }
    int (*F)() = read<int>;
     
    char buff[OUTPUT], *iter = buff;
    template<class T>inline void P(RG T x, RG char ch = '\n')
    {
///*lgg*/cout << x << ch; return;
        static int stack[110]; RG int O = 0; RG char *iter = io::iter;
        if(!x)*iter++ = '0';
        else
        {
            (x < 0) ? x = -x, *iter++ = '-' : 1;
            for(; x; x /= 10) stack[++O] = x % 10;
            for(; O; *iter++ = '0' + stack[O--])
                ;
        }
        *iter++ = ch, io::iter = iter;
    }

    inline void puts(RG const char *s) {while(*s) *iter++ = *s++;}
    inline void output() {fwrite(buff, 1, iter - buff, stdout), iter = buff;}
}
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;
}
int main(){
    freopen("in","r",stdin);    
    freopen("out","w",stdout);
    RG int (*F)() = io::read<int>;
    n=F();m=F();
    n1=sqrt(n);
    for(int i=1;i<=n;++i)a[i]=F(),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);
        }
        for(int j=1;j<=n;++j)tag2[i][j]=tag2[i-1][j]+query(n-j+1);
        for(int j=l;j<=r;++j)add(n-a[j]+1,-1);
        for(int j=r;j>=l;--j){
            rig[j]=query(a[j]);
            if(j!=r)rig[j]+=rig[j+1];
            add(a[j],1);
        }
        for(int j=1;j<=n;++j)tag1[i][j]=tag1[i-1][j]+query(j);
        for(int j=l;j<=r;++j)add(a[j],-1);
    }
    for(int i=1;i<be[n];++i){
        for(int j=(i-1)*n1+1;j<=i*n1;++j)add(n-a[j]+1,1);
        cnt[i][i]=lef[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]+=query(n-a[k]+1);
                add(n-a[k]+1,1);
            }
        }
        for(int j=(i-1)*n1+1;j<=n;++j)add(n-a[j]+1,-1);
    }
    int l,r;
    while(m--){
        l=F();r=F();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);
        }
         io::P(ans);
    }
    io::output();
    close_file();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ZH-comld/p/10449396.html