zoukankan      html  css  js  c++  java
  • 莫队算法

    mind:

    分块

    离散化

    通过合理地对询问排序,然后以较优的顺序暴力回答每个询问(两个指针左右扩张或缩小范围)

    借题理解

    Luogu P3901 数列找不同

    莫队发展里程

    1.首先这个题很明显可以暴力跑,然后开个桶记录一下(慢到家

    2.珂以在区间([1,5])的基础上,去掉位置 (1)(即将左端点右移一位),加上位置 (6)(即将右端点右移一位),得到区间([2,6])的答案
    对于([99999,100000])这样的鬼畜数据肯定会被卡

    所以就莫队就从此把分块纳了进去,先对数据进行了排序,然后在由上述操作锁定区间

    怎样排序捏??

    莫队提供了这样一个排序方案:将原序列以(n^{1/2})为一块进行分块(分块的大小也珂以调整),排序第一关键字是询问的左端点所在块的编号,第二关键字是询问的右端点本身的位置,都是升序。然后我们用上面提到的“移动当前区间左右端点”的方法,按顺序求每个询问区间的答案,移动每一个询问区间左右端点可以求出下一个区间的答案

    排序:

    bool cmp(Query a,Query b)
    { 
        return a.bl==b.bl?a.r<b.r:a.bl<b.bl;
    }
    

    但由于出题人过于狠毒
    又多出一种优化,叫做奇偶优化
    按奇偶块排序。这也是比较通用的。如果区间左端点所在块不同,那么就直接按左端点从小到大排;如果相同,奇块按右端点从小到大排,偶块按右端点从大到小排

    node

     bool cmp(Query a,Query b)
    {
        return a.bl!=b.bl?a.l<b.l:((a.bl&1)?a.r<b.r:a.r>b.r);
    }
    

    核心代码

     sort(q + 1,q + m + 1, cmp);
       for(int i = 1;i <= m; i++){
       	  L = q[i].l,R = q[i].r;
       	  while(nl < L) del(nl++);
    	  while(nl > L) add(--nl);
    	  while(nr < R) add(++nr);
    	  while(nr > R) del(nr--);
    	  if(ans == (R - L + 1)){
    	  	  ANS[q[i].num] = 1;
    	  }  
       }
    

    复杂度

    (O(n*n^{1/2}))

    /*
    work by:Ariel_
    */
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define N 100010
    using namespace std;
    typedef long long ll;
    int read(){
    	int x = 0,f = 1;char c = getchar();
    	while(c < '0'||c > '9'){
    	if(c == '-')f = -1;c = getchar();}
    	while(c >= '0'&& c <= '9'){x = x*10 + c - '0',c = getchar();}
    	return x*f;
    }
    int n,m,lucky_block,L,R,a[N],nl,nr,ANS[N],ans,cnt[N]; 
    struct Query{
    	int l, r , num;
    }q[N];
    bool cmp(Query a,Query b){
        return (a.l/lucky_block) == (b.l/lucky_block) ? a.r < b.r : a.l < b.l;//排序 
    }
    void add(int pos){
    	if(++cnt[a[pos]] == 1) ans++;
    }
    void del(int pos){
    	if(--cnt[a[pos]] == 0) ans--;
    }
    int main(){
       n = read(),m = read();
       lucky_block = sqrt(n);
       for(int i = 1;i <= n; i++){
       	    a[i] = read();
       }
       for(int i = 1; i <= m; i++){
       	   q[i].l = read();
       	   q[i].r = read();
       	   q[i].num = i;
       } 
       sort(q + 1,q + m + 1, cmp);
       
       for(int i = 1;i <= m; i++){
       	  L = q[i].l,R = q[i].r;
       	  while(nl < L) del(nl++);
    	  while(nl > L) add(--nl);
    	  while(nr < R) add(++nr);
    	  while(nr > R) del(nr--);
    	  if(ans == (R - L + 1)){
    	  	  ANS[q[i].num] = 1;
    	  }  
       }
       for(int i = 1;i <= m; i++){
       	   if(ANS[i] == 1){
       	     printf("Yes
    ");	
    	   }
    	   else{
    	   	  printf("No
    ");
    	   }
       } 
    }
    
    
  • 相关阅读:
    C#
    C#
    ssh学习笔记
    (已解决)Could not open '/var/lib/nova/mnt/*/volume-*': Permission denied
    RPCVersionCapError: Requested message version, 4.17 is incompatible. It needs to be equal in major version and less than or equal in minor version as the specified version cap 4.11.
    如何在linux下安装idea
    The system has no LUN copy license
    调整mysql数据库最大连接数
    mysql数据库编码问题
    cinder支持nfs快照
  • 原文地址:https://www.cnblogs.com/Arielzz/p/14127113.html
Copyright © 2011-2022 走看看