题意:
分析:
-
暴力:
区间询问,不强制在线,直接莫队,查询内容是区间逆序对,直接上树状数组,复杂度 (O(nsqrt nlog ))
-
正解:
时限:0.25s 空限:32M
莫队二次离线板子题
众所周知莫队二次离线能快速解决区间逆序对问题我们考虑查询区间从 ([l_1,r_1]) 变为 ([l_1,r_2]) 时值的变化,首先我们规定 (cnt(l_1,r_1,l_2,r_2)) 表示区间 ([l_1,r_1,]) 和区间 ([l_2,r_2]) 的逆序对数
我们先考虑从 ([l,r]) 移动到 ([l,r+1]) , (Delta ans=cnt(l,r,r+1,r+1)) 差分一下 (Delta ans=cnt(1,r,r+1,r+1)-cnt(1,l-1,r+1,r+1)) , 那么从 ([l_1,r_1]) 移动到 ([l_1,r_2]) 时 (displaystyle Delta ans=sum_{i=r_1+1}^{r_2} cnt(1,i-1,i,i)-cnt(1,l-1,r_1+1,r_2))
对于这个式子的前半部分可以直接预处理出来,所以我们要做的就是处理后半部分,这是一个前缀和和区间逆序对的形式,由于莫队的复杂度我们可以知道,这些区间长度之和不会超过 (O(nsqrt n)) 所以我们可以把区间询问分到每一个对应的前缀上,然后每次用指针扫一下前缀,顺便处理一下每一个前缀处的询问,用一个数据结构查询一下
我们发现指针扫描时只会插入 (O(n)) 个数但是有 (O(nsqrt n)) 的询问,所以我们需要一个 (O(sqrt n)) 插入但是能 (O(1)) 查询的数据结构 —— 值域分块
我们按照莫队分 4 种情况讨论:
-
(l<q[i].l)
(displaystyle Delta ans=sum_{i=l}^{q[i].l}cnt(i,i,i+1,r)=sum_{i=l}^{q[i].l}cnt(i,i,1,r)-cnt(i,i,1,i)=cnt(l,q[i].l,1,r)-sum_{i=l}^{q[i].l}cnt(i,i,1,i))
-
(l>q[i].l)
同上,只不过范围变了一下
-
(r<q[i].r)
(displaystyle Delta ans=sum_{i=r+1}^{q[i].r}cnt(l,i-1,i,i)=sum_{i=r+1}^{q[i].r}cnt(1,i-1,i,i)-cnt(1,l-1,i,i)=-cnt(1,l-1,r+1,q[i].r)+sum_{i=r+1}^{q[i].r}cnt(1,i-1,i,i))
-
(r>q[i].r)
同上,范围变一下
总复杂度 (O(nsqrt n+nlog ))
-
代码:
#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
#define lc rt<<1
#define rc rt<<1|1
#define pb push_back
#define fir first
#define sec second
#define inl inline
#define reg register
using namespace std;
namespace zzc
{
typedef long long ll;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const int maxn = 1e5+5;
int n,m,blo,cnt,len,tot;
int c[maxn],d[maxn],t[maxn],bel[maxn],lef[maxn],rig[maxn],w[maxn],tag[maxn];
ll ans[maxn],num1[maxn],num2[maxn];
struct que
{
int l,r,id;
}q[maxn];
bool cmp(que a,que b)
{
return (a.l/blo==b.l/blo)?a.r<b.r:a.l<b.l;
}
struct node
{
int opt,l,r,id;
node(){};
node(int opt,int l,int r,int id):opt(opt),l(l),r(r),id(id){}
};
vector<node> v1[maxn],v2[maxn];
inl int lowbit(int x) {return x&(-x);}
inl void modify(int x,int val=1) {for(int i=x;i<=n;i+=lowbit(i))t[i]+=val;}
inl int query(int x) {int res=0;for(int i=x;i;i-=lowbit(i))res+=t[i];return res;}
void update1(int x)
{
if(tag[bel[x]])for(int i=lef[bel[x]];i<=rig[bel[x]];i++) w[i]+=tag[bel[x]];tag[bel[x]]=0;
for(int i=lef[bel[x]];i<=x;i++) w[i]++;
for(int i=1;i<bel[x];i++) tag[i]++;
}
void update2(int x)
{
if(tag[bel[x]]) for(int i=lef[bel[x]];i<=rig[bel[x]];i++) w[i]+=tag[bel[x]];tag[bel[x]]=0;
for(int i=x;i<=rig[bel[x]];i++) w[i]++;
for(int i=bel[x]+1;i<=tot;i++) tag[i]++;
}
void solve()
{
int id,p,frm,to;
lef[tot=1]=1;
cnt=sqrt(len)+1;
for(int i=1;i<=len;i++) {bel[i]=tot;if(i%cnt==0) rig[tot]=i,lef[++tot]=i+1;}rig[tot]=len;
for(int i=1;i<=n;i++)
{
int siz=v1[i].size();
for(int j=0;j<siz;j++)
{
id=v1[i][j].id;p=v1[i][j].opt;frm=v1[i][j].l;to=v1[i][j].r;
for(int k=frm;k<=to;k++) ans[id]+=1ll*p*(tag[bel[c[k]+1]]+w[c[k]+1]);
}
update1(c[i]);
}
memset(tag,0,sizeof(tag));memset(w,0,sizeof(w));
for(int i=n;i>=1;i--)
{
int siz=v2[i].size();
for(int j=0;j<siz;j++)
{
id=v2[i][j].id;p=v2[i][j].opt;frm=v2[i][j].l;to=v2[i][j].r;
for(int k=frm;k<=to;k++) ans[id]+=1ll*p*(tag[bel[c[k]-1]]+w[c[k]-1]);
}
update2(c[i]);
}
}
void work()
{
n=read();m=read();blo=355;
for(int i=1;i<=n;i++) c[i]=d[i]=read();
sort(d+1,d+n+1);
len=unique(d+1,d+n+1)-d-1;
for(int i=1;i<=n;i++) c[i]=lower_bound(d+1,d+len+1,c[i])-d;
for(int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].id=i;
for(int i=1;i<=n;i++) num1[i]=num1[i-1]+i-1-query(c[i]),modify(c[i]);
memset(t,0,sizeof(t));
for(int i=n;i>=1;i--) num2[i]=num2[i+1]+query(c[i]-1),modify(c[i]);
sort(q+1,q+m+1,cmp);
for(int i=1,l=1,r=0;i<=m;i++)
{
if(l>q[i].l) ans[q[i].id]+=(num2[q[i].l]-num2[l]),v2[r].pb(node(-1,q[i].l,l-1,q[i].id)),l=q[i].l;
if(r<q[i].r) ans[q[i].id]+=(num1[q[i].r]-num1[r]),v1[l].pb(node(-1,r+1,q[i].r,q[i].id)),r=q[i].r;
if(l<q[i].l) ans[q[i].id]+=(num2[q[i].l]-num2[l]),v2[r].pb(node(1,l,q[i].l-1,q[i].id)),l=q[i].l;
if(r>q[i].r) ans[q[i].id]+=(num1[q[i].r]-num1[r]),v1[l].pb(node(1,q[i].r+1,r,q[i].id)),r=q[i].r;
}
solve();
for(int i=1;i<=m;i++) ans[q[i].id] += ans[q[i - 1].id];
for(int i=1;i<=m;i++) printf("%lld
",ans[i]);
}
}
int main()
{
zzc::work();
return 0;
}