二次离线

前置技能

  • 莫队
  • 修改查询 \(O(\sqrt n )-O(1)\) 平衡

概念

  • 考虑朴素莫队离线询问,过程中维护信息从 \([l,r]\) 扩展为 \([l\pm 1,r\pm 1]\) ,本质上就是要询问共 \(O(n\sqrt m)\) 次形如第 \(r\) 个元素与区间 \([l,r-1]\) 产生的贡献。
  • 当然,如果这个贡献可以差分为 \([1,r-1]\) 与 \(r\) 的贡献和 \([1,l-1]\) 与 \(r\) 的贡献,那么就可以尝试使用二次离线了。
  • 具体的,我们发现形如 \([1,r-1]\) 与 \(r\) 的贡献只有 \(n\) 个,可以直接尝试 \(O(n\sqrt n)\) 或 \(O(\ poly(n)\ \log n)\) 等复杂度处理,如果嫌麻烦,也可以放到下一段类似的处理。
  • 然后对于 \(O(n\sqrt m)\) 次询问形如 \([1,k]\) 与 \(r\) 的贡献,我们考虑扫描线,每次从 \([1,k]\) 扩展为 \([1,k+1]\) ,这样一共为 \(n\) 次修改,而在过程中我们要进行 \(O(n\sqrt m)\) 询问。而我们可以调整我们维护数据结构的方式,使得每次扩展的复杂度为 \(O( \sqrt m)\),而询问的复杂度为 \(O(1)\),从而达到平衡复杂度到 \(O(n\sqrt m)\) 级别。

优势

  • 莫队时从 \([l,r]\) 扩展为 \([l\pm 1,r\pm 1]\) 有的时候并不能做到 \(O(1)\),这是因为扩展一次需要查询一次、修改一次,这样修改和查询的次数都为 \(O(n\sqrt m)\), 本身就不太好平衡。
  • 二次离线可以通过差分将莫队扩展区间变成总共 \(O(n)\) 次修改,\(O(n\sqrt m)\) 次查询,就可以平衡了。

扩展

  • 在时间复杂度为 \(O(n \sqrt m)\) 的情况下,其空间复杂度也可以 \(O(n+m)\) 。
  • 首先要求 \([1,r-1]\) 与 \(r\) 的贡献和 \([1,l-1]\) 与 \(r\) 的贡献中 \([1,r-1]\) 与 \(r\) 必须预处理,然后所有 \([1,l-1]\) 与 \(r\) 的贡献对应到每次莫队区间扩展都对应着固定 \(l\),\(r\) 是一个连续的区间,变成 \(O(m)\) 个区间,可以线性空间存储,扫描线时每次 \(O(区间长度)\) 询问即可,总共会询问 \(O(n\sqrt m)\) 次,空间线性。

例题

  • 洛谷P5047 Yuno loves sqrt technology II
  • 离线求区间逆序对,空间 \(32MB\)
  • 具体题解就不写了,具体可以参考代码。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define debug(x) cerr<<#x<<" = "<<x
#define sp <<" "
#define el <<endl
#define fgx cerr<<" -------------------------------------------------------- "<<endl
#define LL long long
#define DB double
#define LDB long double
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
inline int read(){
int nm=0; bool fh=true; char cw=getchar();
for(;!isdigit(cw);cw=getchar()) fh^=(cw=='-');
for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
return fh?nm:-nm;
}
#define M 100020
#define B 330
int n,m,c[M],H[M],be[M],L[620],R[620],tot,tt1,tt2,d1,d2;
LL pr[M],sf[M],S[M],ans[M],cur,A[M],W[620]; pii T[M];
inline void add(int k,int dt){for(;k<=n;k+=(k&-k))c[k]+=dt;}
inline int qry(int k,int res=0){for(;k;k-=(k&-k))res+=c[k];return res;}
struct Q{
int id,ls,rs;
inline void gtin(int ID){id=ID,ls=read(),rs=read();}
inline bool operator <(const Q&ot)const{
if(be[ls]!=be[ot.ls]) return be[ls]<be[ot.ls];
if(be[ls]&1) return rs<ot.rs; return rs>ot.rs;
}
}q[M];
struct _Q{
int kt,ps,to,ls,rs; _Q(){}
_Q(int _kt,int _ps,int _to,int _ls,int _rs){kt=_kt,ps=_ps,to=_to,ls=_ls,rs=_rs;}
}pre[M],suf[M];
bool cmp_pre(_Q a,_Q b){return a.ps<b.ps;}
bool cmp_suf(_Q a,_Q b){return a.ps>b.ps;}
inline void ins(int x){for(int k=be[x];k<=tot;k++)++W[k];for(int k=x,TP=R[be[x]];k<=TP;++k)++A[k];}
inline int calc(int x){return W[be[x]-1]+A[x];}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++) H[i]=read(),T[i]=mp(H[i],i); sort(T+1,T+n+1);
for(int i=1;i<=n;i++) H[T[i].second]=i; LL Now=0;
for(L[tot=1]=1,R[tot]=B;R[tot]<n;++tot,L[tot]=R[tot-1]+1,R[tot]=R[tot-1]+B); R[tot]=n;
for(int i=1;i<=n;i++) be[i]=(i-1)/B+1;
for(int i=1;i<=n;i++) Now+=i-1-qry(H[i]),add(H[i],1),pr[i]=Now;
for(int i=1;i<=n;i++) add(H[i],-1),sf[i]=Now,Now-=qry(H[i]);
for(int i=1;i<=m;i++) q[i].gtin(i); sort(q+1,q+m+1);
for(int l=1,r=1,i=1;i<=m;i++){
if(r<q[i].rs) S[i]+=pr[q[i].rs]-pr[r],pre[++tt1]=_Q(-1,l-1,i,r+1,q[i].rs),r=q[i].rs;
if(l>q[i].ls) S[i]+=sf[q[i].ls]-sf[l],suf[++tt2]=_Q(-1,r+1,i,q[i].ls,l-1),l=q[i].ls;
if(r>q[i].rs) S[i]-=pr[r]-pr[q[i].rs],pre[++tt1]=_Q(1,l-1,i,q[i].rs+1,r),r=q[i].rs;
if(l<q[i].ls) S[i]-=sf[l]-sf[q[i].ls],suf[++tt2]=_Q(1,r+1,i,l,q[i].ls-1),l=q[i].ls;
} sort(pre+1,pre+tt1+1,cmp_pre),sort(suf+1,suf+tt2+1,cmp_suf),d1=d2=1;
while(d1<=tt1&&(!pre[d1].ps)) ++d1; while(d2<=tt2&&suf[d2].ps>n) ++d2;
for(int i=1;i<=n&&d1<=tt1;i++)
for(ins(H[i]);d1<=tt1&&pre[d1].ps==i;S[pre[d1].to]+=(LL)pre[d1].kt*(LL)(pre[d1].rs-pre[d1].ls+1)*(LL)i,++d1)
for(int k=pre[d1].ls;k<=pre[d1].rs;++k) S[pre[d1].to]-=pre[d1].kt*calc(H[k]);
memset(A,0,sizeof(A)),memset(W,0,sizeof(W));
for(int i=n;i>0&&d2<=tt2;--i) for(ins(H[i]);d2<=tt2&&suf[d2].ps==i;++d2)
for(int k=suf[d2].ls;k<=suf[d2].rs;++k) S[suf[d2].to]+=suf[d2].kt*calc(H[k]);
for(int i=1;i<=m;i++) cur+=S[i],ans[q[i].id]=cur;
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0;
}

有关二次离线和 Yuno loves sqrt technology II的更多相关文章

  1. 题解 Yuno loves sqrt technology II

    题目传送门 题目大意 有\(n\)个数,\(m\)个查询,每次查询一个区间内的逆序对个数. \(n,m\le 10^5\) 思路 其实是为了锻炼二次离线才做这道题的. 不难想到可以有一个\(\Thet ...

  2. [Ynoi2019模拟赛]Yuno loves sqrt technology II(二次离线莫队)

    二次离线莫队. 终于懂了 \(lxl\) 大爷发明的二次离线莫队,\(\%\%\%lxl\) 二次离线莫队,顾名思义就是将莫队离线两次.那怎么离线两次呢? 每当我们将 \([l,r]\) 移动右端点到 ...

  3. [Ynoi2019模拟赛]Yuno loves sqrt technology II

    题目大意: 给定一个长为\(n\)的序列,\(m\)次询问,每次查询一个区间的逆序对数. 32MB. 解题思路: 出题人题解 众所周知lxl是个毒瘤,Ynoi道道都是神仙题 二次离线莫队. 对于每个区 ...

  4. 洛谷 P5048 - [Ynoi2019 模拟赛] Yuno loves sqrt technology III(分块)

    题面传送门 qwq 感觉跟很多年前做过的一道题思路差不多罢,结果我竟然没想起那道题?!!所以说我 wtcl/wq 首先将 \(a_i\) 离散化. 如果允许离线那显然一遍莫队就能解决,复杂度 \(n\ ...

  5. [Luogu5048] [Ynoi2019模拟赛]Yuno loves sqrt technology III[分块]

    题意 长为 \(n\) 的序列,询问区间众数,强制在线. \(n\leq 5\times 10^5\). 分析 考虑分块,暴力统计出整块到整块之间的众数次数. 然后答案还可能出现在两边的两个独立的块中 ...

  6. [luogu5048] [Ynoi2019模拟赛] Yuno loves sqrt technology III

    题目链接 洛谷. Solution 思路同[BZOJ2724] [Violet 6]蒲公英,只不过由于lxl过于毒瘤,我们有一些更巧妙的操作. 首先还是预处理\(f[l][r]\)表示\(l\sim ...

  7. [洛谷P5048][Ynoi2019模拟赛]Yuno loves sqrt technology III

    题目大意:有$n(n\leqslant5\times10^5)$个数,$m(m\leqslant5\times10^5)$个询问,每个询问问区间$[l,r]$中众数的出现次数 题解:分块,设块大小为$ ...

  8. 洛谷P5048 [Ynoi2019模拟赛]Yuno loves sqrt technology III(分块)

    传送门 众所周知lxl是个毒瘤,Ynoi道道都是神仙题 用蒲公英那个分块的方法做结果两天没卡过去→_→ 首先我们分块,预处理块与块之间的答案,然后每次询问的时候拆成整块和两边剩下的元素 整块的答案很简 ...

  9. Luogu P5048 [Ynoi2019模拟赛]Yuno loves sqrt technology III 分块

    这才是真正的$N\sqrt{N}$吧$qwq$ 记录每个数$vl$出现的位置$s[vl]$,和每个数$a[i]=vl$是第几个$vl$,记为$P[i]$,然后预处理出块$[i,j]$区间的答案$f[i ...

随机推荐

  1. 如何查看FQDN

    FQDNFully Qualified Domain Name缩写, 含义完整域名. 例, 台机器主机名(hostname)www, 域缀(domain)example.com, 该主机FQDN应该w ...

  2. Summer training round2 #8(Training26)

    A:贪心DFS 先从最远的搜起 如果一个点的value>=2 就ans++ D:并查集 E:大模拟 F:快速幂 #include <bits/stdc++.h> using name ...

  3. windows时钟服务设置

    运行Regedit,打开注册表编辑器. 找到注册表项HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config\,将Anno ...

  4. Nginx 的简介

    1. 什么是 nginx :Nginx 是高性能的 HTTP 和反向代理的服务器,处理高并发能力是十分强大的,能经受高负 载的考验,有报告表明能支持高达 50,000 个并发连接数.  2. 正向代理 ...

  5. electron仿制qq(2) 主界面制作

    制作从头开始 最后会将写好的组件放到一起的!之前写了好几天的纯css 有点累 本章中将使用sass 如果代码太长 会分两个或多个章节写代码中会有详细的注释 以便于大家阅读and理解界面可能会有部分偏差 ...

  6. 优秀.NET界面控件DevExpress v19.1.6全新来袭!新改进抢“鲜”看

    DevExpress Universal Subscription(又名DevExpress宇宙版或DXperience Universal Suite)是全球使用广泛的.NET用户界面控件套包,De ...

  7. beanFactory & FactoryBean区别

    FactoryBean Spring内部实现的一种规范& 开头作为beanName Spring中所有的容器都是FactoryBean 因为容器本身也由容器管理, root来创建 都是单列在I ...

  8. [Linux系统] (2)用户权限管理

    示例---普通用户之间的文件共享:假设公司有2个项目组,共享同一台服务器. 1.为两个项目组各创建一个用户: useradd leo01 useradd leo02 2.为两个新用户设置密码: pas ...

  9. R & and &&

    https://blog.csdn.net/jining11/article/details/84933110 和C中的&不用,不要用&&,一般情况都是用&表示并且

  10. Tomcat 激活spring profile

    springboot打包war部署到外部tomcat的时候指定profile启动 windows 在%tomcat%/bin下创建setenv.bat文件 linux 在%tomcat%/bin下创建 ...