莫队算法~练习一
Posted whitelily
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了莫队算法~练习一相关的知识,希望对你有一定的参考价值。
莫队算法~练习一
gym卡了莫队,于是趁这个机会学一下莫队
莫队的核心是分块排序,这种特殊的排序方法将任务按排序后的顺序完成,可以在解决绝大多数无修改的离线区间问题中极大的优化时间(优化了$sqrt n$左右)。
Sona
题意:n个数,寻问10000次,任意区间内的相等数的次数的立方和。
题解:将n个数离散化后,用莫队将询问分块排序,暴力计算出答案,在按原顺序输出结果。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
ll n,a[100007],t,head,maze,size,ak[100007],num[100007],ans[100007],b[100007];
struct madoka{
ll l;
ll r;
ll p;
}ma[100007];
long long int qpow(long long int x,long long int n)
{
long long int res=1;
while(n>0)
{
if(n%2==1)
{
res=res*x;
res=res;
}
x=x*x;
x=x;
n>>=1;
}
return res;
}
bool cmp(madoka a1,madoka a2){
if(ak[a1.l]==ak[a2.l]){
return a1.r<a2.r;
}
return ak[a1.l]<ak[a2.l];
}
void go(){
ll l=1,r=1,ansn=1;
num[a[1]]++;
for(int i=1;i<=t;i++){
while(r<ma[i].r){
r++;
ansn-=qpow(num[a[r]],3);
num[a[r]]++;
ansn+=qpow(num[a[r]],3);
}
while(l>ma[i].l){
l--;
ansn-=qpow(num[a[l]],3);
num[a[l]]++;
ansn+=qpow(num[a[l]],3);
}
while(r>ma[i].r){
ansn-=qpow(num[a[r]],3);
num[a[r]]--;
ansn+=qpow(num[a[r]],3);
r--;
}
while(l<ma[i].l){
ansn-=qpow(num[a[l]],3);
num[a[l]]--;
ansn+=qpow(num[a[l]],3);
l++;
}
ans[ma[i].p]=ansn;
}
}
int main(){
while(scanf("%lld",&n)!=EOF){
memset(num,0,sizeof(num));
size=(ll)sqrt(n*1.0);
maze=ceil((double)n/size);
head=1;
for(int i=1;i<=maze;i++){
for(int j=head;j<head+size&&j<=n;j++){
ak[j]=i;
}
head+=size;
}
int m=0;
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
b[++m]=a[i];
}
sort(b+1,b+1+m);
m=unique(b+1,b+1+m)-b-1;
for(int i=1;i<=n;++i)
a[i]=lower_bound(b+1,b+1+m,a[i])-b;
scanf("%lld",&t);
for(int i=1;i<=t;i++){
scanf("%lld%lld",&ma[i].l,&ma[i].r);
ma[i].p=i;
}
sort(ma+1,ma+1+t,cmp);
go();
for(int i=1;i<=t;i++){
printf("%lld
",ans[i]);
}
}
//return 0;
}
Little Elephant and Array
题意:n个数,寻问10000次,任意区间内的相等数的次数与其数相等的个数。
题解:与上题差不多,但有个坑要注意下,离散化后会导致值改变,所以某数的次数要与它离散化前比较,之后便是莫队板子。
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m,t,a[100007],b[100007],num[100007],size,maze,head,ak[100007],ans[100007];
struct madoka{
int l;
int r;
int p;
}ma[100007];
bool cmp(madoka a1,madoka a2){
if(ak[a1.l]==ak[a2.l]){
return a1.r<a2.r;
}
return ak[a1.l]<ak[a2.l];
}
void go(){
int l=2,r=1,ansn=0;
for(int i=1;i<=t;i++){
while(r<ma[i].r){
r++;
if(num[a[r]]==b[a[r]]){
ansn--;
}
num[a[r]]++;
if(num[a[r]]==b[a[r]]){
ansn++;
}
}
while(r>ma[i].r){
if(num[a[r]]==b[a[r]]){
ansn--;
}
num[a[r]]--;
if(num[a[r]]==b[a[r]]){
ansn++;
}
r--;
}
while(l>ma[i].l){
l--;
if(num[a[l]]==b[a[l]]){
ansn--;
}
num[a[l]]++;
if(num[a[l]]==b[a[l]]){
ansn++;
}
}
while(l<ma[i].l){
if(num[a[l]]==b[a[l]]){
ansn--;
}
num[a[l]]--;
if(num[a[l]]==b[a[l]]){
ansn++;
}
l++;
}
ans[ma[i].p]=ansn;
}
}
int main(){
scanf("%d%d",&n,&t);
size=sqrt(n);
maze=ceil((double)n/size);
head=1;
for(int i=1;i<=maze;i++){
for(int j=head;j<head+size&&j<=n;j++){
ak[j]=i;
}
head+=size;
}
int m=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[++m]=a[i];
}
sort(b+1,b+1+m);
m=unique(b+1,b+1+m)-b-1;
for(int i=1;i<=n;i++){
a[i]=lower_bound(b+1,b+1+m,a[i])-b;
}
for(int i=1;i<=t;i++){
scanf("%d%d",&ma[i].l,&ma[i].r);
ma[i].p=i;
}
sort(ma+1,ma+1+t,cmp);
go();
for(int i=1;i<=t;i++){
printf("%d
",ans[i]);
}
}
以上是关于莫队算法~练习一的主要内容,如果未能解决你的问题,请参考以下文章