Yuno loves sqrt technology I 题解

申明:由于本人卡常技艺不佳,本题解复杂度正确但无法通过

首先分块,然后考虑分开计算贡献维护,看下面一张图:

我们将贡献拆分为 \(ans(A) + ans(B) + ans(C) + ans(AB) + ans(AC) + ans(BC)\),然后考虑逐一维护。

首先散块内部先离散化,然后用树状数组记录散块前后缀逆序对数量,然后散块对整块的贡献考虑枚举散块中的数,然后对于每个块的结尾记录一个前缀和查询时差分求出贡献,散块对散块的贡献考虑将两个块先通过离散化后的数桶排一遍,然后归并排序计算贡献,整块之间的贡献直接预处理时递推处理。总复杂度 \(O(n \sqrt n + n \log n)\)

然后就是常数巨大的代码,代码中写了注释可以辅助理解:

#include<bits/stdc++.h>
#define lowbit(x)(x&(-x))
#define ll long long
namespace IO{
	const int SIZE=1<<21;
	static char ibuf[SIZE],obuf[SIZE],*iS,*iT,*oS=obuf,*oT=oS+SIZE-1;
    int qr;
    char qu[55],c;
    bool f;
	#define getchar() (IO::iS==IO::iT?(IO::iT=(IO::iS=IO::ibuf)+fread(IO::ibuf,1,IO::SIZE,stdin),(IO::iS==IO::iT?EOF:*IO::iS++)):*IO::iS++)
	#define putchar(x) *IO::oS++=x,IO::oS==IO::oT?flush():0
	#define flush() fwrite(IO::obuf,1,IO::oS-IO::obuf,stdout),IO::oS=IO::obuf
	#define puts(x) IO::Puts(x)
	template<typename T>
    inline void read(T&x){
    	for(f=1,c=getchar();c<48||c>57;c=getchar())f^=c=='-';
    	for(x=0;c<=57&&c>=48;c=getchar()) x=(x<<1)+(x<<3)+(c&15); 
    	x=f?x:-x;
    }
    template<typename T>
    inline void write(T x){
        if(!x) putchar(48); if(x<0) putchar('-'),x=-x;
        while(x) qu[++qr]=x%10^48,x/=10;
        while(qr) putchar(qu[qr--]);
    }
    inline void Puts(const char*s){
    	for(int i=0;s[i];i++)
			putchar(s[i]);
		putchar('\n');
	}
	struct Flusher_{~Flusher_(){flush();}}io_flusher_;
}
using IO::read;
using IO::write;
using namespace std;
const int maxn = 1e5+14;
const int maxsq = 320;
int n,m;
inline ll w(vector<int> &A,vector<int> &B){
    int l1=0,l2=0;
    ll res=0;
    vector<int> r;
    while(l1<A.size()||l2<B.size()){
        if(l1==A.size()){
            res+=(A.size()-l1);
            r.push_back(B[l2]);
            ++l2;
        }
        else if(l2==B.size()){
            r.push_back(A[l1]);
            ++l1;
        }
        else if(A[l1]<B[l2]){
            r.push_back(A[l1]);
            ++l1;
        }
        else{
            res+=(A.size()-l1);
            r.push_back(B[l2]);
            ++l2;
        }
    }
    A=r;
    return res;
}
int sq;//块长
int cnt[maxn][maxsq];//前 i 个块中小于等于 j 的数的数量
int a[maxn];//序列
int pre[maxn],suf[maxn];//块内逆序对数量前缀后缀 
int L[maxn],R[maxn],F[maxn];//每个块的起点终点 每个数所属的块
int rk[maxn];//每个数在块中的排名
ll G[maxsq][maxsq];//块 [l,r] 中的逆序对数量
int block_cnt[maxsq];
int tr[maxsq];
inline void add(int x){
    while(x<=sq) tr[x]++,x+=lowbit(x);
}
inline int ask(int x){
    int res=0;
    while(x>0) res+=tr[x],x-=lowbit(x);
    return res;
}
inline void rksort(vector<int> &A){//排序
    for(int x:A){
        block_cnt[rk[x]]=x;
    }
    A.clear();
    for(int i=1;i<=sq;i=-~i){
        if(block_cnt[i]!=0){
            A.push_back(block_cnt[i]);
            block_cnt[i]=0;
        }
    }
    return ;
}
inline void block_init(int pos){
    for(int i=L[pos];i<=R[pos];i=-~i){
        G[pos][pos]+=(i-L[pos])-ask(rk[a[i]]);
        add(rk[a[i]]);
        pre[i]=G[pos][pos];
    }
    for(int i=1;i<=sq;++i) tr[i]=0;
    
    for(int i=R[pos];i>=L[pos];--i){
        suf[i]=suf[i+1]+ask(rk[a[i]]);
        add(rk[a[i]]);
    }
    for(int i=1;i<=sq;++i) tr[i]=0;
}
inline void init(){
    sq = sqrt(n);
    for(int i=1;i<=n;i=-~i){
        if((i - 1)%sq == 0) F[i]=F[i-1]+1,L[F[i]]=i,R[F[i-1]]=i-1;
        else F[i]=F[i-1]; 
    }
    R[F[n]]=n;
    //编号处理
    for(int i=1;i<=n;i=-~i){
        for(int j=F[i];j<=F[n];++j){
            ++cnt[a[i]][j];
        }
    }
    for(int j=1;j<=F[n];++j){
        for(int i=1;i<=n;i=-~i) cnt[i][j]+=cnt[i-1][j];
    }
    //桶处理
    for(int i=1;i<=F[n];i=-~i){
        vector<int> p;
        for(int j=L[i];j<=R[i];++j) p.push_back(a[j]);
        sort(p.begin(),p.end());
        for(int j=0;j<p.size();++j){
            rk[p[j]]=j+1;
        }
    }
    //排序
    for(int i=1;i<=F[n];i=-~i) block_init(i);
    for(int i=1;i<=F[n];i=-~i){
        for(int j=i+1;j<=F[n];++j){
            G[i][j]=G[i][j-1]+G[j][j];
            for(int k=L[j];k<=R[j];++k){
                G[i][j]+=(R[j-1]-L[i]+1)-(cnt[a[k]][j-1]-cnt[a[k]][i-1]);
            }
        }
    }
}
inline ll query(ll l,ll r){
    l=min(l,n*1ll),r=min(r,n*1ll);
    if(l>r){
        return 0;
    }
    if(F[l]==F[r]){
        int res=0;
        if(l!=L[F[r]]){
            res+=(pre[r]-pre[l-1]);
            vector<int> A,B;
            for(int i=L[F[r]];i<l;i=-~i) A.push_back(a[i]);
            for(int i=l;i<=r;i=-~i) B.push_back(a[i]);
            rksort(A);
            rksort(B);
            res-=w(A,B);
        }
        else{
            res=pre[r];
        }
        return res;
    }
    int bl=F[l]+1,br=F[r]-1;
    if(F[r]==F[l]+1){
        ll res=0;
        res+=(suf[l]+pre[r]);
        vector<int> A,B;
        for(int i=l;i<=R[F[l]];i=-~i) A.push_back(a[i]);
        for(int i=L[F[r]];i<=r;i=-~i) B.push_back(a[i]);
        rksort(A);
        rksort(B);
        res+=w(A,B);
        return res;
    }
    ll res=0;
    //整块 散块 块内贡献
    res+=(suf[l]+pre[r]+G[bl][br]);
    //散块对散块的贡献
    vector<int> A,B;
    for(int i=l;i<=R[F[l]];i=-~i) A.push_back(a[i]);
    for(int i=L[F[r]];i<=r;i=-~i) B.push_back(a[i]);
    rksort(A);
    rksort(B);
    res+=w(A,B);
    //散块对整块
    for(int i=l;i<=R[F[l]];i=-~i){
        res+=cnt[a[i]][br]-cnt[a[i]][bl-1];
    }
    //整块对散块
    for(int i=L[F[r]];i<=r;i=-~i){
        res+=(R[br]-L[bl]+1)-(cnt[a[i]][br]-cnt[a[i]][bl-1]);
    }
    return res;
}
ll lstans;
signed main(){
    read(n);
    read(m);
    for(int i=1;i<=n;i=-~i){
        read(a[i]);
    }
    init();
    while(m--){
        ll l,r;
        read(l);
        read(r);
        write(lstans=query(l^lstans,r^lstans));
        putchar('\n');
    }
}
posted @ 2024-01-31 00:00  ChiFAN鸭  阅读(11)  评论(0编辑  收藏  举报