时代的眼泪
题解
变成时代的眼泪了。
貌似是一个奇怪的区间顺序对问题。
数据范围
n
⩽
1
0
5
n\leqslant 10^5
n⩽105,大概是树套树或者分块,感觉分块比较可行,考虑分块。
原题相当于就是求
∑
i
<
j
,
i
,
j
∈
[
x
,
x
′
]
[
y
⩽
p
i
<
p
j
⩽
y
′
]
\sum_{i<j,i,j\in[x,x']}[y\leqslant p_i<p_j\leqslant y']
∑i<j,i,j∈[x,x′][y⩽pi<pj⩽y′],我们就对它们的下标分块,方便维护第一维。
然后考虑之后怎么计算答案。
首先是整块内部的贡献,由于对于一个整块,不同意义的
[
x
′
,
y
′
]
[x',y']
[x′,y′]只有不超过
B
2
B^2
B2种,我们完全可以暴力将它们都计算出来。
也就是说我们把原来的询问离散化到块内的
B
B
B个点上,然后可以区间
d
p
dp
dp计算答案。
我们的离散化显然不能每次都
lower_bound
\text{lower\_bound}
lower_bound,所以需要对于每个块再预处理一下每个值会被离散化到哪个点上。
这部分是
O
(
n
B
+
n
2
B
)
O\left(nB+\frac{n^2}{B}\right)
O(nB+Bn2)的。
那么整块之间的贡献怎么计算呢?
我们先预处理出来当前块中每个点与其它块之间的答案,这可以通过归并得到,按它们的值排序做个前缀和,再按块的顺序做个前缀和。这显然是
O
(
n
B
)
O\left(nB\right)
O(nB)的。
这样,我们稍微差分一下,就能达到当前块中某个前缀关于它前面块的顺序对总个数。
我们再按之前离散化得到的值,差分就能得到当前块中在
[
y
,
y
′
]
[y,y']
[y,y′]中的数关于前面块的顺序对数。
最后,还需要再减去当前块中
[
y
,
y
′
]
[y,y']
[y,y′]中的数与前面块小于
y
y
y的数形成的顺序对。由于两者是必然形成顺序对的,之间统计前面块在
[
1
,
y
′
)
[1,y')
[1,y′)中有多少数即可。这需要做一个块前缀和的前缀和,同样能
O
(
n
2
B
)
O\left(\frac{n^2}{B}\right)
O(Bn2)地解决。
这部分还是
(
n
B
)
\left(nB\right)
(nB)的。
接下来考虑散块与整块的贡献。
诶,这可以通过我们块前缀和的前缀和差分得到。
直接在散块的位置把关于它前面或后面的顺序对算一算即可。
然后就是散块内部的贡献了,这个可以通过在块内算一下每个点的前缀顺序对数量,然后差分得到。
只有当每个点在区间
[
y
,
y
′
]
[y,y']
[y,y′]中时,才统计它的贡献,还得减去它前面小于
y
y
y的数的数量。
这部分是
O
(
m
B
)
O\left(mB\right)
O(mB)的。
至于散块与散块的贡献,整块内我们是预先排好序了的,把散块的按顺序提出来归并一下就行了。
这也是
O
(
m
B
)
O\left(mB\right)
O(mB)的。
所以总时间复杂度是 O ( n 2 B + ( n + m ) B ⩾ n n + m ) O\left(\frac{n^2}{B}+(n+m)B\geqslant n\sqrt{n+m}\right) O(Bn2+(n+m)B⩾nn+m)。
源码
写还是比较好写,但调有点难调,不过完全不卡常。不卡常的Ynoi
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
#define MAXN 100005
#define MAXM 200005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lowbit(x) (x&-x)
const int mo=998244353;
const int inv2=5e8+4;
const int jzm=2333;
const int zero=15;
const LL INF=0x3f3f3f3f3f3f3f3f;
const double Pi=acos(-1.0);
const double eps=1e-9;
const int lim=1000000;
const int orG=3,ivG=332748118;
const int n1=500;
const int M=MAXN/n1+5,N=n1+5;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,m,a[MAXN],block[MAXN],L[M],R[M],b[M][N],len[M];
int val[N][M],sum[N][M],pid[MAXN],ta[N],tb[N],lena,lenb;
int rg[N][N],psum[M][MAXN],pd[N][N],d[N];
LL ans[MAXM],pre[N][M];
struct ming{int l,r,x,y;}s[MAXM];
bool cmp(int x,int y){return a[x]<a[y];}
int main(){
read(n);read(m);
for(int i=1;i<=n;i++)read(a[i]);
for(int i=1;i<=n;i++)block[i]=(i+n1-1)/n1;
for(int i=1;i<=n;i++){if(!L[block[i]])L[block[i]]=i;R[block[i]]=i;}
for(int i=1;i<=block[n];i++){
len[i]=R[i]-L[i]+1;
for(int j=1;j<=len[i];j++)
b[i][j]=j+L[i]-1;
sort(b[i]+1,b[i]+len[i]+1,cmp);
}
for(int i=1;i<=m;i++)read(s[i].l),read(s[i].r),read(s[i].x),read(s[i].y);
for(int i=1;i<=block[n];i++)
for(int j=1,k=1;j<=n;j++){
if(a[b[i][k]]==j)k++;
psum[i][j]=psum[i-1][j]+k-1;
}
for(int i=1;i<=block[n];i++){
for(int j=L[i];j<=R[i];j++)d[j-L[i]+1]=a[j];
for(int j=1;j<i;j++)
for(int ki=1,kj=1;ki<=len[i]||kj<=len[j];)
if(ki>len[i]||(kj<=len[j]&&a[b[j][kj]]<a[b[i][ki]]))kj++;
else val[ki][j]=kj-1,ki++;
for(int j=1;j<=len[i];j++)
for(int k=1;k<i;k++)
sum[j][k]=sum[j][k-1]+val[j][k];
for(int j=1;j<=len[i];j++)for(int k=1;k<i;k++)
pre[j][k]=pre[j-1][k]+sum[j][k];
for(int j=n,k=len[i];j>0;j--){if(j<a[b[i][k]]&&k)k--;pid[j]=k;}
for(int ltn=2;ltn<=len[i];ltn++)
for(int l=1,r=ltn;r<=len[i];l++,r++)
rg[l][r]=rg[l+1][r]+rg[l][r-1]-rg[l+1][r-1]+(b[i][l]<b[i][r]);
for(int j=1;j<=len[i];j++)
for(int k=1;k<j;k++)
pd[j][k]=pd[j][k-1]+(d[j]>d[k]);
for(int j=1;j<=m;j++){
if(block[s[j].l]<i&&i<block[s[j].r]){
int al=block[s[j].l],ar=i-1;
ans[j]+=pre[pid[s[j].y]][ar]-pre[pid[s[j].y]][al];
ans[j]-=pre[pid[s[j].x-1]][ar]-pre[pid[s[j].x-1]][al];
ans[j]-=1ll*(pid[s[j].y]-pid[s[j].x-1])*(psum[ar][s[j].x-1]-psum[al][s[j].x-1]);
ans[j]+=rg[pid[s[j].x-1]+1][pid[s[j].y]];
continue;
}
if(block[s[j].l]==i&&block[s[j].r]==i){
int l=s[j].l-L[i]+1,r=s[j].r-L[i]+1,now=0;
for(int k=l;k<=r;k++){
if(s[j].x<=d[k]&&d[k]<=s[j].y)
ans[j]+=pd[k][k-1]-pd[k][l-1]-now;
if(d[k]<s[j].x)now++;
}
continue;
}
if(block[s[j].l]==i){
int l=s[j].l-L[i]+1,r=len[i],p=block[s[j].r]-1,now=0;
for(int k=l;k<=r;k++){
if(s[j].x<=d[k]&&d[k]<=s[j].y){
ans[j]+=pd[k][k-1]-pd[k][l-1]-now;
ans[j]+=psum[p][s[j].y]-psum[p][d[k]]-psum[i][s[j].y]+psum[i][d[k]];
}
if(d[k]<s[j].x)now++;
}
continue;
}
if(block[s[j].r]==i){
int l=1,r=s[j].r-L[i]+1,p=block[s[j].l],now=0;
for(int k=l;k<=r;k++){
if(s[j].x<=d[k]&&d[k]<=s[j].y){
ans[j]+=pd[k][k-1]-pd[k][l-1]-now;
ans[j]+=psum[i-1][d[k]]-psum[i-1][s[j].x-1]-psum[p][d[k]]+psum[p][s[j].x-1];
}
if(d[k]<s[j].x)now++;
}
continue;
}
}
}
for(int i=1;i<=m;i++){
if(block[s[i].l]==block[s[i].r])continue;lena=lenb=0;
int bl=block[s[i].l],br=block[s[i].r];
for(int j=1;j<=len[bl];j++)if(b[bl][j]>=s[i].l)ta[++lena]=a[b[bl][j]];
for(int j=1;j<=len[br];j++)if(b[br][j]<=s[i].r)tb[++lenb]=a[b[br][j]];
for(int j=1,k=1,num=0;j<=lena||k<=lenb;)
if(j>lena||(k<=lenb&&tb[k]<ta[j])){
if(s[i].x<=tb[k]&&tb[k]<=s[i].y)ans[i]+=num;k++;
}
else num+=(s[i].x<=ta[j]&&ta[j]<=s[i].y),j++;
}
for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
return 0;
}