(描述:我是谁,我在哪?开玩笑,本来我现在应该写5级题的,但是最近有几个算法经常在我眼前晃悠,splay,莫队算法,还有昨天晚上zjx学长告诉我的悬线法,让我非常的好奇,另外就是5级题有些知识内容不会,没办法写,所以我现在也在补算法知识,顺便了解一下)
莫队算法:
1.莫队算法的核心代码(挪动的方式):
/*1.一般挪动方式,复杂度O(n*m)*/
inline void add(int x){//添加
cnt[x]++;
if(cnt[x] == 1) ans++;
}
inline void del(int x){//删除
cnt[x]--;
if(cnt[x] == 0) ans--;
}
// 在获取答案时
while(l > q[i].l) add(a[--l]);
while(r < q[i].r) add(a[++r]);
while(l < q[i].l) del(a[++l]);
while(r > q[i].r) del(a[--r]);
2.莫队算法的两种排序方式:
(1)第一种我看懂了,就是以右端点为第一关键字排序
代码:
//正常的排序方式
bool cmp(query a,query b){
return (a.r/block)==(b.r/block) ? a.l < b.l : a.r < b.r;
}
(2)第二种说是奇偶性排序,但是我不太懂???
//奇偶性排序
bool cmp(node a,node b){
return pos[a.l]^pos[b.l]?(pos[a.l]<pos[b.l]):(pos[a.l]&1?a.r < b.r:a.r > b.r);
}
/*这样能快的原因是因为指针移到右边后不用再跳回左边,
而跳回左边处理下一个块又要跳回右边,
这样能减少一半操作,理论上能快一倍
*/
3.莫队算法的分块方式:
块的大小是不固定的,但是要怎么分呢???不太懂
4.例题:
题意:求一个区间中每个数出现次数的平方和
还是设 cnt_i 为i在当前区间出现的次数
如果 cnt_i 多了一个,那
ans+=2 * cnt[x]+1
如果 cnt_i 多了一个,那
ans-=2 * cnt[x]-1
代码实现:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
ll c[maxn];
ll sum[maxn];
struct node{
ll l;
ll r;
ll num;
}q[maxn];
ll anss[maxn];
ll block;
ll ans = 0;
bool cmp(node a,node b){
return (a.r / block) == (b.r / block) ? a.l < b.l : a.r < b.r;
}
inline void add(int x){//添加操作
sum[c[x]]++;
ans = ans + (2 * sum[c[x]] - 1);//想一想完全平方公式
}
inline void del(int x){//删除操作
sum[c[x]]--;
ans = ans - (2 * sum[c[x]] + 1);
}
int main(){
ll n,m,k;
scanf("%lld%lld%lld",&n,&m,&k);//输入
block = sqrt(n);//分块
for(ll i = 1;i <= n;i++){//输入
scanf("%lld",&c[i]);
}
for(ll i = 1;i <= m;i++){
scanf("%lld%lld",&q[i].l,&q[i].r);
q[i].num = i;
}
sort(q + 1,q + 1 + m,cmp);//排序
int l = 1; int r = 0;
for(ll i = 1;i <= m;i++){//离线查询
ll ql = q[i].l; ll qr = q[i].r;
while(l < ql){
del(l++);
}
while(r > qr){
del(r--);
}
while(l > ql){
add(--l);
}
while(r < qr){
add(++r);
}
anss[q[i].num] = ans;
}
for(ll i = 1;i <= m;i++){//输出答案
printf("%lld\n",anss[i]);
}
return 0;
}```