题目:
问在区间[l,r]和[l1,r1]内x的出现次数的乘积是多少?
题解:
莫队算法的模板题
关于莫队算法你可以参考这个
我这里简单的说说我对莫队的理解:
莫队是一个优雅的暴力,就是将原本复杂度不能过的程序进行优化,莫队是通过分块来实现
如果暴力做这个题,查询区间[l,r]内x的数量我们可能就从头开始搜查,按照题目给的数据来搜查,但其实我们可以这样优化,比如题目给的查询区间[3,4],[2,4],[1,5],我们可以先查询[1,5],然后顺势查询[2,4],最后[3,4],而非从头开始,这样就省了不少时间。那如何实现这个?我们可以对整体进行分块,然后按照所分的快进行排序,尽可能实现查询区间时省时省力,最后再输出答案
至于为什么要分块排序呢?可以看看莫队算法的讲解
很显然这是一个离线算法,且适合查询量很大的情况
代码如下
代码:
#include<bits/stdc++.h> #define forn(i,a,b) for(ll i=a;i<=b;i++) #define INF 0x3f3f3f3f using namespace std; #define ll long long const ll N =100*1000+10; const ll mod = 20180623; ll n,m; ll a[N],ans[N*2],num[N],pos[N]; struct node{ ll L,R,x,id; }t[N*2]; bool cmp(node a,node b){ if(pos[a.L]==pos[b.L]) return a.R<b.R; else return pos[a.L]<pos[b.L]; } ll L=1,R=0; void solve(node p){ while(p.L>L){ num[a[L]]--; L++; } while(p.R>R){ R++; num[a[R]]++; } while(p.L<L){ L--; num[a[L]]++; } while(p.R<R){ num[a[R]]--; R--; } } int main(){ scanf("%lld %lld",&n,&m); memset(num,0,sizeof(num)); ll block=sqrt(n); for(ll i=1;i<=n;i++){ scanf("%lld",a+i); pos[i]=i/block; } for(ll i=1;i<=m;i++){ ll l1,r1,l2,r2,x; scanf("%lld%lld%lld%lld%lld",&l1,&r1,&l2,&r2,&x); if(l1>r1)swap(l1,r1); if(l2>r2)swap(l2,r2); t[i].L=l1; t[i].R=r1; t[i].id=i; t[i].x=x; t[i+m].L=l2; t[i+m].R=r2; t[i+m].id=i+m; t[i+m].x=x; } sort(t+1,t+1+2*m,cmp); memset(num,0,sizeof(num)); for(ll i=1;i<=2*m;i++){ solve(t[i]); ans[t[i].id]=num[t[i].x]; } for(ll i=1;i<=m;i++) printf("%lld\n%lld\n%lld\n",ans[i]%mod,ans[i+m]%mod,(ans[i]%mod*ans[i+m])%mod); return 0; }