题解 P5046【[Ynoi2019 模拟赛] Yuno loves sqrt technology I】
题意
给你一个长度为 的排列 , 次询问区间逆序对个数,强制在线。
时间 750ms,.
思路
其实是算有贡献的二元组 的个数。
排列其实没有什么性质,只是避免了相等情况的讨论。
于是显然会想到分类讨论:
设左散块、整块、右散块分别为 ,询问左端为块 ,右端为块 , 的右端点为 , 的左端点为 。
- :预处理每个位置到块末的答案 即可。答案为 。
- :预处理每个位置到块首的答案 即可。答案为 。
- :预处理每两个块间的答案 即可。答案为 。
- :预处理前 块中小于 的数 即可。答案为 。
- :用上一类的东西即可。答案为 。
- :预处理块内排序。将两散块排序后的数组归并比计算即可。
但我们忽略了一点:当 同块时没有处理。但我们预处理出 ( 同块)并适当压缩空间即可。
这样做到了总时空 。
但是,由于常数较大,我不经任何常数处理的代码只能得到 分。
于是我们需要优化:
- 调块长:喜闻乐见。根据常数调到 。
- 预处理削常数: 和 用 直接得到, 用二维前缀和,减少树状数组或者值域分块的使用。
- 询问削常数:如果 那么我们就用到 的答案容斥掉多算的部分。左散块同理。
居然就能过了,这比第四分块的卡常简单些。
代码好写,以下代码仅供参考:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
}
const int N=1e5+10,sq=170,nq=N/sq+10;
int n,q,blk,a[N],pre[N],bl[nq],br[nq],bel[N];
int pr[N],sf[N],f[nq][N],h[N][sq+10],se[nq][nq];
ll g[nq][nq],last;
struct Tem{
int x,id;
inline friend bool operator<(const Tem &a,const Tem &b){
return a.x<b.x;
}
}b[N];
inline void init(int id,int l,int r){
int p=l-1;
for(int i=l;i<=r;i++)
f[id][a[i]]++;
for(int i=l;i<=r;i++)
b[i].x=a[i],b[i].id=i;
sort(b+l,b+r+1);
for(int j=l;j<=r;j++)
for(int i=j-1;i>=l;i--)
h[i][j-l]=h[i+1][j-l]+h[i][j-1-l]-h[i+1][j-1-l]+(a[i]>a[j]);
for(int i=l+1;i<=r;i++)
pr[i]=h[l][i-l];
for(int i=r-1;i>=l;i--)
sf[i]=h[i][r-l];
}
int s1[N],s2[N];
int main(){
n=read(),q=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n;i+=sq){
blk++;
bl[blk]=i,br[blk]=min(i+sq-1,n);
for(int j=bl[blk];j<=br[blk];j++)
bel[j]=blk;
init(blk,bl[blk],br[blk]);
g[blk][blk]=pr[br[blk]];
}
for(int i=1;i<=blk;i++)
for(int j=1;j<=n;j++)
f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
for(int i=1;i<=blk;i++)
for(int j=i;j<=blk;j++){
int tmp=0;
for(int k=bl[j];k<=br[j];k++)
tmp+=f[i][a[k]];
se[i][j]=tmp;
}
for(int j=1;j<=blk;j++)
for(int i=j-1;i>=1;i--){
ll cnt=g[i][j-1]+g[i+1][j]-g[i+1][j-1];
for(int k=bl[i];k<=br[i];k++)
cnt+=f[j][a[k]]-f[j-1][a[k]];
g[i][j]=cnt;
}
while(q--){
int l=read()^last,r=read()^last;
int bL=bel[l],bR=bel[r];
if(bL==bR){
last=h[l][r-bl[bL]];
}else{
last=sf[l]+pr[r]+g[bL+1][bR-1];
int len=br[bR-1]-bl[bL+1]+1;
for(int i=l;i<=br[bL];i++)
last+=f[bR-1][a[i]]-f[bL][a[i]];
int L=bl[bR],R=br[bR];
if(R-r-1<r-L){
last+=(r-L+1ll)*len-(se[bR-1][bR]-se[bL][bR]);
for(int i=r+1;i<=R;i++)
last+=f[bR-1][a[i]]-f[bL][a[i]];
}else{
for(int i=L;i<=r;i++)
last+=len-f[bR-1][a[i]]+f[bL][a[i]];
}
int top1=0,top2=0;
for(int i=bl[bL];i<=br[bL];i++)
if(b[i].id>=l) s1[++top1]=b[i].x;
for(int i=bl[bR];i<=br[bR];i++)
if(b[i].id<=r) s2[++top2]=b[i].x;
int i=0,j=0,c=0;
for(;i<top1&&j<top2;)
if(s1[i+1]<s2[j+1]) last+=c,i++;
else c++,j++;
last+=1ll*c*(top1-i);
}
write(last),putc('\n');
}
flush();
}
再见 qwq~
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)