topic
Give you a sequence a(0<=ai<=1e9) of length n(1<=n<=1e5),
m(1<=m<=1e5) times of query, querying the reverse logarithm of an interval [l,r] each time, which can be offline.
source of ideas
Getting Started with Value Domain Blocking_ChiFAN_'s Blog - CSDN Blog
answer
Mo team offline for the second time:
1. Ordinary Mo team to find the number of reversed pairs in the interval, it is Mo team + tree array to find the reversed pair, the complexity
When inserting/deleting a value v, it actually requires the number of numbers larger/smaller than v in the current interval [l,r]①, use a tree array to find
And ① can continue to be offline, which is transformed into finding the number of numbers [1, r] larger/smaller than v-[1,l-1] the number of numbers larger/smaller than v
There are a total of mo team inquiries, prefix offline modification,
Therefore, one needs to be inserted, and the data structure of O(1) query is required. This is the value domain block
a[i] represents the value of the i position, and the ordinary team/block is divided into blocks according to i, that is, divided into blocks according to the position
And the value domain block : block by the number of occurrences of the value
cnt[i]: the number of occurrences of the value i, each occurrence is divided into one piece,
In this way, the insertion can be realized , and the query of O(1)
Maintain the prefix and / suffix sum of the number within the block, the prefix and / suffix sum of the number between blocks,
When inserting, modify a block + position in the block, query O(1) query
the complexity
the code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int N=100005;
int n,m;ll a[N];
inline int lowbit(int x){return x&-x;}
ll c[N],sz=0;
int p[N];bool cmp(int x,int y){return a[x]<a[y];}
inline void add(int x,ll k){sz+=k;for(;x<=n;x+=lowbit(x))c[x]+=k;}
inline ll getsum(int x){ll ans=0;for(;x;x-=lowbit(x))ans+=c[x];return ans;}
ll L[N],R[N];//L[i]:1~i-1有多少个数大于a[i];R[i]:i+1~n有多少个数小于a[i]
const int block=310;
struct ASK
{
int l,r,p;
}ask[N];
inline bool mmp(ASK n1,ASK n2)
{
if(n1.l/block!=n2.l/block)return n1.l<n2.l;
if((n1.l/block)&1)return n2.r<n1.r;
return n1.r<n2.r;
}
struct node{int l,r,p,op;};
vector<node>ls[N],rs[N];
int B,bl[N/block+5],br[N/block+5],w[N];
int s[N/block+5],C[N];
ll ret[N],ans[N];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
p[i]=i;
}
sort(p+1,p+n+1,cmp);
ll tmp=a[p[1]];a[p[1]]=1;
for(int i=2,t=1;i<=n;i++)
{
if(a[p[i]]!=tmp)t++;
tmp=a[p[i]];a[p[i]]=t;
}//离散化
for(int i=1;i<=n;i++)
{
L[i]=L[i-1]+sz-getsum(a[i]);
add(a[i],1);//L[i]转前缀和
}//for(int i=1;i<=n;i++)printf("%lld ",L[i]);puts("");
memset(c,0,sizeof(c));
for(int i=n;i>=1;i--)
{
R[i]=R[i+1]+getsum(a[i]-1);
add(a[i],1);//R[i]转后缀和
}//for(int i=1;i<=n;i++)printf("%lld ",R[i]);puts("");
for(int i=1;i<=m;i++)
{
scanf("%d%d",&ask[i].l,&ask[i].r);
if(ask[i].l>ask[i].r)swap(ask[i].l,ask[i].r);
ask[i].p=i;
}
sort(ask+1,ask+m+1,mmp);//排序
ask[0]=(ASK){1,0,0};
for(int i=1;i<=m;i++)//莫队二次离线
{//把莫队的移动离线下来
ret[i]=L[ask[i].r]-L[ask[i-1].r]+R[ask[i].l]-R[ask[i-1].l];
if(ask[i].r>ask[i-1].r)rs[ask[i-1].l-1].push_back((node){ask[i-1].r+1,ask[i].r,i,-1});
else if(ask[i].r<ask[i-1].r)rs[ask[i-1].l-1].push_back((node){ask[i].r+1,ask[i-1].r,i, 1});
if(ask[i].l<ask[i-1].l)ls[ask[i ].r+1].push_back((node){ask[i].l,ask[i-1].l-1,i,-1});
else if(ask[i].l>ask[i-1].l)ls[ask[i ].r+1].push_back((node){ask[i-1].l,ask[i].l-1,i, 1});
}
B=(n-1)/block+1;
for(int i=1;i<=B;i++)
{
bl[i]=br[i-1]+1;
br[i]=br[i-1]+block;
}br[B]=n;//值域分块
for(int i=1;i<=B;i++)for(int j=bl[i];j<=br[i];j++)w[j]=i;
for(int i=1;i<=n;i++)
{
for(int j=1;j<w[a[i]];j++)s[j]++;
for(int j=bl[w[a[i]]];j<=a[i];j++)C[j]++;
for(int j=0;j<rs[i].size();j++)
{
node t=rs[i][j];
int l=t.l,r=t.r;
tmp=0;
for(int k=l;k<=r;k++)tmp+=s[w[a[k]+1]]+C[a[k]+1];
ret[t.p]+=t.op*tmp;
}
}
memset(C,0,sizeof(C));
memset(s,0,sizeof(s));
for(int i=n;i>=1;i--)
{
for(int j=w[a[i]]+1;j<=B;j++)s[j]++;
for(int j=a[i];j<=br[w[a[i]]];j++)C[j]++;
for(int j=0;j<ls[i].size();j++)
{
node t=ls[i][j];
int l=t.l,r=t.r;
tmp=0;
for(int k=l;k<=r;k++)tmp+=s[w[a[k]-1]]+C[a[k]-1];
ret[t.p]+=t.op*tmp;
}
}
for(int i=1;i<=m;i++)
{
ret[i]+=ret[i-1];//ret最终的值是差分值
ans[ask[i].p]=ret[i];
}
for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
return 0;
}