• 莫队 + 带修莫队


    莫队其实就是一个带优化的暴力,通过将区间询问按一定规则进行排序,从而优化过程,求出答案。

    举一例子:(例子不具备权威性,只是让读者了解莫队是干啥的)

    /*
    输入四个区间
    
    1  4     初始条件,L= R = 0,     将R遍历到4    需要走4步   L走一步,共5次   
    4  8   继承上一次 L 和 R 的值,L从1到4   需要3次,R从4到8,需4次,  总计8次     
    2  9   同理继承,   L回退2次,  R前进一次                        总计3次      
    1  2   同理,L回退1次,R回退7次                                 总计8次                          
    
    
    如果直接暴力,计算机将要计算     5+8+3+8=24次
    
    
    如果将询问进行排序呢?假设排列成如下模样:
    
    1 2              总走3次
    1 4           总走2次
    2 9           总走6次
    4 8            总走3次  
    
    
    全局总走3+2+6+3=14次,这相差是不是很大?这也是莫队的思想,将暴力优化。   
    */

    至于如何将询问排序,证明就有一点烦恼,直接说结论:

    可以借助分块思想,假设总区间为n,那么每一块区间长度应趋近于    n^(2.0/3)

    可以将询问中的  L或者是 R,按其所在块的编号,  从小到大排序,然后再慢慢暴力。。。这就是莫队,说一下莫队的数据极限是     5e5,超过1e7,则需要另谋高就。

    附上一题:P1494 [国家集训队]小Z的袜子

    对于该题,有着优化操作,也是组合公式的直接约分简化。

    方案1

        

    方案2:

    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map> 
    #include<algorithm>
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    #define Mem0(x) memset(x,0,sizeof(x))
    #define Mem1(x) memset(x,-1,sizeof(x))
    #define MemX(x) memset(x,0x3f,sizeof(x))
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f;
    const double pi=acos(-1.0);
    
    
    const int N=500010;
    int B,ans[N][5],fz,fm,len,n,m,col[N],cnt[N];
    struct s{
    	int l,r,id;
    	bool operator < (s&b)
    	{
    		return l/B==b.l/B?r<b.r:l<b.l;
    	}
    }q[N];    
    
    void init()
    {
    	len=fz=fm=0;
    	memset(cnt,0,sizeof(cnt));
    	cin>>n>>m;		B=sqrt(n);
    	for (int i=1;i<=n;i++){
    		cin>>col[i];
    	}
    	
    	for (int i=0;i<m;i++){
    		cin>>q[i].l>>q[i].r;
    		q[i].id=i;
    	}
    	sort(q,q+m);
    }
    bool cmp(s&a,s&b)
    {
    	if (a.l/B==b.l/B)
    		return a.l>b.l;
    }
    void add(int x)
    {
    	fz+=cnt[x];
    	cnt[x]++;
    	fm+=len;
    	len++;
    }
    void delect(int x)
    {
    	cnt[x]--;
    	fz-=cnt[x];
    	len--;
    	fm-=len;
    }
    int main()
    {
    	init(); 
    	int l=1,r=0;
    	for (int i=0;i<m;i++){
    		if (q[i].l==q[i].r){
    			ans[q[i].id][0]=0;
    			ans[q[i].id][1]=1;
    			continue;
    		}
    		while (l<q[i].l){
    			delect(col[l++]);
    		}
    		while (l>q[i].l){
    			add(col[--l]);
    		}
    		while (r<q[i].r){
    			add(col[++r]);
    		}
    		while (r>q[i].r){
    			delect(col[r--]);
    		}
    		int tmp=__gcd(fz,fm);
    		ans[q[i].id][0]=fz/tmp;
    		ans[q[i].id][1]=fm/tmp;
    	}
    	for (int i=0;i<m;i++){
    		printf("%d/%d
    ",ans[i][0],ans[i][1]);
    	}
    	return 0;
    }
    

      

    带修莫队就是带上了修改。。。。    (待更新)

    *****************************************更新******************************************

     简单的来说:

      带修莫队  =  莫队    + 时间轴  

    对于原来莫队,就是先对  询问 L按所在分块编号从小到大排序,当相等的时候则按 R 所在分块的从大到小排序。

    至于带修莫队,就是在原莫队上再加一轴(时间轴),先将l分块,再讲r分块,同一块的按 t 排序。

        排好序之后,查询遍历,如果当前修改次数 比 本次查询改的多,则改回去,反之则再次修改,直到修改次数与本次查询改的次数相同。

  • 相关阅读:
    c++ 反汇编 堆变量
    glibc源码逆向——fread函数
    glibc源码逆向——fopen
    buu查漏补缺刷题(3)
    gyctf_2020_borrowstack
    实现用句柄表反调试
    pwnable_orw 学习shellcraft新花样
    buu查漏补缺刷题(2)
    gdb调试源码
    buu查漏补缺刷题(1)
  • 原文地址:https://www.cnblogs.com/q1204675546/p/11304003.html
Copyright © 2020-2023  润新知