• 莫队算法


    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
    ");
    	   }
       } 
    }
    
    
  • 相关阅读:
    Java 练习(经典例题: 生产者/消费者问题)
    Java 基础(线程的通信)
    Java 练习(线程的同步)
    Java 基础( ReentrantLock )
    Java 基础(线程的死锁问题)
    Java基础(单实例设计模式懒汉式解决线程安全)
    Java 基础(同步方法解决线程安全问题)
    Java 基础(Thread类的有关方法,线程的调度)
    Java 基础(线程的生命周期, 同步代码块解决线程安全)
    Java 基础(以实现 Runnable 接口的方式创建多线程)
  • 原文地址:https://www.cnblogs.com/Arielzz/p/14127113.html
Copyright © 2020-2023  润新知