莫队算法

思想:

  不修改的时间复杂度 为n*logn 修改的n*pow(n,0.6666)

   在队列里通过l,r 更新区间的答案;

   不过要分 根号n 的版块 进行(特殊)排序;

  代码:

struct sfs{
    int l,r,pos,id; // pos 板块 
    bool operator <(const sfs b)const 
    {
        if(pos==b.pos)
        {
            if(r==b.r) return l<b.l;
            return r<b.r;
        }
        return pos<b.pos;
    }
}p[M];
View Code

 栗子很重要,要看

HH 有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答,因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。

输入格式
第一行:一个整数  ,表示项链的长度。

第二行: 个整数,表示依次表示项链中贝壳的编号(编号为  到  之间的整数)。

第三行:一个整数  ,表示HH询问的个数。

接下来  行:每行两个整数, 和 ,表示询问的区间。

输出格式
 行,每行一个整数,依次表示询问对应的答案。

样例
输入样例:
6  
1 2 3 4 3 5  
3  
1 2   
3 5  
2 6  
输出样例:
2  
2  
4  
数据范围与提示
,
 ,  。
View Code

 代码

//1 出现的思想
//2 cmp 的各个的写法

#include <bits/stdc++.h>
using namespace std;
#define ri register int
#define M 1000005 

struct sfs{
    int l,r,pos,id; // pos 板块 
    bool operator <(const sfs b)const 
    {
        if(pos==b.pos)
        {
            if(r==b.r) return l<b.l;
            return r<b.r;
        }
        return pos<b.pos;
    }
}p[M];
int ans[M];

int col[M];

int n,m;

void readyy()
{
    scanf("%d",&n);
    for(ri i=1;i<=n;i++)
    scanf("%d",&col[i]);
    
    scanf("%d",&m);
    
    int d=int(sqrt(n)+0.5); /// REMEMBER
    
    for(ri i=1;i<=m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        p[i].pos=a/d;
        p[i].l=a,p[i].r=b,p[i].id=i;
    }
    sort(p+1,p+1+m);
}
int num[M];int cur;
void jia(int a)
{
    if(!num[col[a]]) cur++;
    num[col[a]]++;    
}
void jian(int a)
{
    if(num[col[a]]==1) cur--;
    num[col[a]]--;
}
void solv()
{
    int l=p[1].l;
    int r=l;
    jia(r); // 起始点 // 函数此时可以正常编译 莫md 
    while(r<p[1].r)
    {
        jia(++r);
    }
    ans[p[1].id]=cur;
//    printf("%d\n",r); 
    for(ri i=2;i<=m;i++) // 是从第二个开始 
    {
        // 下面写法 可以 就是让 l,r到达想要的地方。 
        while(l<p[i].l) jian(l++); // 到达那个的点不用减去,起始的点要减去;以下同理可得 
        while(l>p[i].l) jia(--l);
        while(r<p[i].r) jia(++r);
        while(r>p[i].r) jian(r--);
        ans[p[i].id]=cur;  
    }
    
    for(ri i=1;i<=m;i++)
    printf("%d\n",ans[i]);
    
}
int main(){
    
    readyy();
    solv();
    return 0; 
    
}

  
View Code

 修改莫队

 

struct dian{
    int l,r,pos,id,tim;
    bool operator <(const dian &t)const 
    {
        if(pos==t.pos) 
          {
              if(r/d==t.r/d) return tim<t.tim;
              return r<t.r;
          }
          return l<t.l;
    }
}p[M];
void work (int v,int k)
{  
    vis[cent[v]]--;
    cent[v]+=k;
    vis[cent[v]]++;
}
void work_tim(int ti,int i)
{
    if(p[i].l<=gai[ti].mubiao&&gai[ti].mubiao<=p[i].r)
        {
            work(val[gai[ti].mubiao],-1);
            work(gai[ti].VAL,1);
        }
        swap(val[gai[ti].mubiao],gai[ti].VAL);
}
d=pow(n,0.6666);
    for(ri i=1;i<=m;i++)
    {   int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        if(a==1)
        {
            p[++trmp].l=b;
            p[trmp].r=c;
            p[trmp].id=trmp;p[trmp].tim=sj;
            p[trmp].pos=p[trmp].l/d;
        }
        else
        {
          gai[++sj].mubiao=b;
          tt[n+sj]=gai[sj].VAL=c;    
        }
    }
    sort(p+1,p+trmp+1);
    sj=0;
    for(ri i=p[1].l;i<=p[1].r;i++)
    {    
         work(val[i],1);      
    }
    int baba;
    while(sj<p[1].tim) work_tim(++sj,1);
    while(sj>p[1].tim) work_tim(sj--,1);  // li hai
    for (ANS[p[1].id]=1;vis[ANS[p[1].id]]>0;ANS[p[1].id]++);
    for(ri i=2;i<=m;i++)
    {
        int l=p[i-1].l;
        int r=p[i-1].r;
        
        while(l<p[i].l) work(val[l++],-1);
        while(r>p[i].r) work(val[r--],-1);
        while(l>p[i].l) work(val[--l],1);
        while(r<p[i].r) work(val[++r],1);
        while(sj<p[i].tim) work_tim(++sj,i);
         while(sj>p[i].tim) work_tim(sj--,i);  
        //跟新ans 
        } 
View Code

 注意 d的取值为什么有时取 pow(n,0.6666)呢 而不是 int(0.5+sqrt(n))

原文地址:https://www.cnblogs.com/Lamboofhome/p/11709877.html