码迷,mamicode.com
首页 > 编程语言 > 详细

# 莫队算法小结(待更新)

时间:2019-10-19 12:51:49      阅读:97      评论:0      收藏:0      [点我收藏+]

标签:关键字   ++i   code   clu   复杂   两个指针   gcd   std   toc   

莫队算法小结(待更新)

简单介绍

博客安利:

  1. OI Wiki
  2. 大米饼

解决一类离线区间查询问题,分块思想,时间复杂度\(O(n\sqrt n)\)

  • 排序

    读入的时候对整个数组进行分块,块大小一般使用\(\sqrt n\),对询问操作排序的时候,先以块号为第一关键字,\(r\)为第二关键字,从小到大排序,然后逐个遍历

    离线后将询问排序,顺序处理每个询问,暴力从上一个区间的答案转移到下一个区间的答案(通过两个指针的\(++\)\(--\)操作实现)

  • 指针移动

    技术图片

    \(l\)指针从绿色区域向右移动一格,更新操作对应,先减去cnt[绿色]的共享,cnt[绿色]\(--\),再加上cnt[绿色]区域的贡献,其他指针移动操作类似。

基础莫队

  • 题目链接:

    给出n只袜子颜色,每次给个区间\([l,r]\),询问这个区间连续取两只袜子取到同一种颜色的概率。

  • 思路:

    对于L,R的询问。

    设其中颜色为x,y,z的袜子的个数为a,b,c..…

    那么答案即为 \((a*(a-1)/2+b*(b-1)/2+c*(c-1)/2....)/((R-L+1)*(R-L)/2)\)

    化简得: \((a^2+b^2+c^2+...x^2-(a+b+c+d+.....))/((R-L+1)*(R-L))\)

    即: \((a^2+b^2+c^2+...x^2-(R-L+1))/((R-L+1)*(R-L))\)

    我们需要解决的一个问题是:求一个区间内每种颜色数目的平方和。

  • AcCode:

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=5e4+5;
//存储询问区间
struct node{int l,r,id;LL A,B;}q[maxn];
//in[]存储每个数所在的区间
int n,m,a[maxn],in[maxn];
//处理前预排序
inline bool cmp(node& a,node& b){
    return in[a.l]==in[b.l]?a.r<b.r:a.l<b.l;
}
//处理完,返回原来询问的顺序
inline bool CMP(node& a,node& b){return a.id<b.id;}
//cnt[]存储每个数的个数
int ans,cnt[maxn];
LL pow(LL x){return x*x;}
inline void update(int x,int d){
    ans-=pow(cnt[a[x]]),cnt[a[x]]+=d,ans+=pow(cnt[a[x]]);
}
inline void solve(){
    int l=1,r=0;
    for(int i=1;i<=m;++i){
        while(l<q[i].l)update(l,-1),l++;
        while(l>q[i].l)update(l-1,1),l--;
        while(r<q[i].r)update(r+1,1),r++;
        while(r>q[i].r)update(r,-1),r--;

        if(l==r){q[i].A=0,q[i].B=1;continue;}
        q[i].A=ans-(r-l+1);
        q[i].B=1LL*(r-l+1)*(r-l);
        LL gc=__gcd(q[i].A,q[i].B);
        q[i].A/=gc,q[i].B/=gc;
    }
}
int main(){
    cin>>n>>m;
    int sqr=sqrt(n);
    for(int i=1;i<=n;++i)cin>>a[i],in[i]=i/sqr+1;
    for(int i=1;i<=m;++i)cin>>q[i].l>>q[i].r,q[i].id=i;
    
    sort(q+1,q+1+m,cmp);
    
    solve();
    
    sort(q+1,q+1+m,CMP);
    
    for(int i=1;i<=m;++i)
        printf("%lld/%lld\n",q[i].A,q[i].B);
    return 0;
}

带修莫队

树上莫队

# 莫队算法小结(待更新)

标签:关键字   ++i   code   clu   复杂   两个指针   gcd   std   toc   

原文地址:https://www.cnblogs.com/sstealer/p/11703307.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!