zoukankan      html  css  js  c++  java
  • 莫队阶段小结

    莫队阶段小结

    首先,为什么要叫小结呢,因为我只学了一点点,后续可能更多

    莫队

    莫队是一种离线处理区间问题的神器.答题思路就是你将原数列分成(sqrt{n})块,将所有查询左端点定位,并按照左端点所在的块进行排序,相同则按照右端点排序

    大体就是这个样子

    inline bool cmp(Q x,Q y){
        return belong[x.li] == belong[y.li] ? x.ri < y.ri : x.li < y.li;
    }
    

    这样的话我们每个快内都暴力求

    时间复杂度为(O(msqrt{n}))

    但是还有一种玄学加速方式,十分有用

    inline bool cmp(Q x,Q y){
        return belong[x.li] ^ belong[y.li] ? belong[x.li] < belong[y.li] : belong[x.li] & 1 ? x.ri < y.ri : x.ri > y.ri;
    }
    

    会快很多.

    之后我们每次维护取件区间,和当前左右端点.每次发现不在当前区域内就暴力跳的同时修改信息

      int nowl = 1,nowr = 0;
        for(int i = 1;i <= m;++i){
            int L = q[i].li,R = q[i].ri;
            while(nowl > L) add(--nowl);
            while(nowr < R) add(++nowr);
            while(nowl < L) del(nowl++);
            while(nowr > R) del(nowr--);	
        	//统计答案
        }
    

    另外注意应当先拓展后收缩,为了该开始改成负数之类的东西。

    接下来放几道例题

    luoguP3901 数列找不同

    莫队的板子题了,我们维护(sum_i)表示(i)这个数当前出现了多少次,(ans)表示当前出现次数(>=2)的数的个数

    每次修改时更新(sum)(ans),之后统计答案即可

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    using namespace std;
    const int N = 1e5 + 3;
    int a[N],ans[N];
    int sum[N];
    int n,m,now = 0,bl;
    int belong[N],block;
    inline int read(){
        int v = 0,c = 1;char ch = getchar();
        while(!isdigit(ch)){
            if(ch == '-') c = -1;
            ch = getchar();
        }
        while(isdigit(ch)){
            v = v * 10 + ch - 48;
            ch = getchar(); 
        }
        return v * c;
    }
    struct Q{
    	int li,ri;	
    	int id;
    }q[N];
    inline bool cmp(Q x,Q y){
    	return belong[x.li] == belong[y.li] ? x.ri < y.ri : x.li < y.li;
    }
    inline void add(int x){
    	x = a[x];
    	++sum[x];
    	if(sum[x] == 2) now++;
    }
    inline void del(int x){
    	x = a[x];
    	--sum[x];
    	if(sum[x] == 1) now--;
    }
    int main(){
    	n = read(),m = read();
    	for(int i = 1;i <= n;++i) a[i] = read();
    	bl = sqrt(n);
    	for(int i = 1;i <= n;++i) belong[i] = i / bl;
    	for(int i = 1;i <= m;++i) q[i].li = read(),q[i].ri = read(),q[i].id = i;
    	sort(q + 1,q + m + 1,cmp);
    	int nowl = 1,nowr = 0;
    	for(int i = 1;i <= m;++i){
    		int L = q[i].li,R = q[i].ri;
    		while(nowl < L) del(nowl++);
    		while(nowl > L) add(--nowl);
    		while(nowr > R) del(nowr--);
    		while(nowr < R) add(++nowr);
    		ans[q[i].id] = now;
    	}
    	for(int i = 1;i <= m;++i){
    		if(ans[i]) printf("No
    ");
    		else printf("Yes
    ");
    	}
    	return 0;	
    }
    

    CF375D Tree and Queries

    虽然是树上问题,但是所有的询问都是针对子树,我们就可以针对他的欧拉序进行操作.
    但是比较棘手的是所有的(k_i)可能不相同,

    我们就设(sum_i)表示(>=i)的数的个数

    (val_i)表示(i)的出现次数

    每次修改统计即可

    答案就是(sum[k_i])

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    using namespace std;
    const int N = 1e5 + 3;
    int n,m;
    vector <int> G[N];
    int v[N],sum[N],val[N];
    int l[N],r[N],c[N];
    int belong[N];
    int ans[N],tot,cnt,bl;
    struct Q{
    	int li,ri;
    	int id;
    	int ko;	
    }q[N];
    inline int read(){
        int v = 0,c = 1;char ch = getchar();
        while(!isdigit(ch)){
            if(ch == '-') c = -1;
            ch = getchar();
        }
        while(isdigit(ch)){
            v = v * 10 + ch - 48;
            ch = getchar(); 
        }
        return v * c;
    }
    inline void dfs(int x,int f){
    	c[++cnt] = v[x];
    	l[x] = cnt;
    	for(int i = 0;i < (int)G[x].size();++i){
    		int y = G[x][i];
    		if(y == f) continue;
    		dfs(y,x);	
    	}
    	r[x] = cnt;
    }
    inline bool cmp(Q x,Q y){
    	return belong[x.li] == belong[y.li] ? x.ri < y.ri : x.li < y.li;	
    }
    //sum[i]:>=i的数的种类数
    //val[i]:i出现次数 
    inline void add(int x){
    	x = c[x];
    	val[x]++;
    	sum[val[x]]++;
    }
    inline void del(int x){
    	x = c[x];
    	sum[val[x]]--;
    	val[x]--;
    }
    int main(){
    	n = read(),m = read();
    	for(int i = 1;i <= n;++i) v[i] = read();
    	for(int i = 1;i < n;++i){
    		int x = read(),y = read();
    		G[x].push_back(y);G[y].push_back(x);	
    	}
    	dfs(1,0);
    //	cout << "GG" << endl; 
    //	for(int i = 1;i <= n;++i) printf("%d %d
    ",l[i],r[i]);cout << "GG"  << endl;
    	bl = sqrt(n);
    	for(int i = 1;i <= n;++i) belong[i] = i / bl;
    	for(int i = 1;i <= m;++i){
    		int x = read();
    		q[i].li = l[x];
    		q[i].ri = r[x];
    		q[i].ko = read();
    		q[i].id = i;
    	}
    	sort(q + 1,q + m + 1,cmp);
    	int nowl = 1,nowr = 0;
    	for(int i = 1;i <= m;++i){
    		int L = q[i].li,R = q[i].ri;
    		while(nowl > L) add(--nowl);
    		while(nowl < L) del(nowl++);
    		while(nowr < R) add(++nowr);
    		while(nowr > R) del(nowr--);
    		ans[q[i].id] = sum[q[i].ko];
    	}
    	for(int i = 1;i <= m;++i) printf("%d
    ",ans[i]);
    	return 0;	
    }
    

    luoguP4396 [AHOI2013]作业

    这道题和上几道不大一样,发现不了区间限制之外,还有值域的限制

    我们就用树状数组维护值域

    但是这样的时间复杂度为(nsqrt{n}logn)

    其实跑(10^5)是挺虚的,还好题目(3s),这道题有(nsqrt{n})的做法,先咕一咕

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    using namespace std;
    const int N = 1e5 + 3;
    int a[N],ans[N],belong[N];
    int ans2[N],ans1[N];
    int n,m,bl;
    int maxx;
    int book[N];
    struct Q{
        int li,ri;
        int ai,bi;
        int id;
    }q[N << 1];
    struct BIT{
        int c[N << 3];
        inline void add(int x,int v){
            for(;x <= maxx;x += x & -x) c[x] += v;    
        }
        inline int query(int x){
            int res = 0;
            for(;x;x -= x & -x) res += c[x];
            return res; 
        }
    };
    BIT T1,T2;
    inline int read(){
        int v = 0,c = 1;char ch = getchar();
        while(!isdigit(ch)){
            if(ch == '-') c = -1;
            ch = getchar(); 
        }
        while(isdigit(ch)){
            v = v * 10 + ch - 48;
            ch = getchar(); 
        }
        return v * c;
    }
    inline bool cmp(Q x,Q y){
    	return belong[x.li] ^ belong[y.li] ? belong[x.li] < belong[y.li] : belong[x.li] & 1 ? x.ri < y.ri : x.ri > y.ri;
    }
    //int ans = 0;
    inline void add(int x){
    	x = a[x];
    	if(book[x] == 0) T2.add(x,1);
    	book[x]++;
    	T1.add(x,1);
    }
    inline void del(int x){
    	x = a[x];
    	if(book[x] == 1) T2.add(x,-1);
    	book[x]--;
    	T1.add(x,-1);
    }
    int main(){
    	n = read(),m = read();
    	bl = sqrt(n);
    	for(int i = 1;i <= n;++i) {
    		a[i] = read() + 1,belong[i] = i / bl;
    		maxx = max(maxx,a[i]);
    	}
    	for(int i = 1;i <= m;++i){
    		q[i].li = read(),q[i].ri = read();
    		q[i].ai = read() + 1,q[i].bi = read() + 1;	
    		if(q[i].ai > q[i].bi) swap(q[i].ai,q[i].bi);
    		q[i].id = i;
    		maxx = max(q[i].ai,max(maxx,q[i].bi));
    	}
    	sort(q + 1,q + m + 1,cmp);
    	int nowl = 1,nowr = 0;
    	for(int i = 1;i <= m;++i){
    		int L = q[i].li,R = q[i].ri;
    		while(nowl > L) add(--nowl);
    		while(nowr < R) add(++nowr);
    		while(nowl < L) del(nowl++);
    		while(nowr > R) del(nowr--);	
    		ans1[q[i].id] = T1.query(q[i].bi) - T1.query(q[i].ai - 1);
    		ans2[q[i].id] = T2.query(q[i].bi) - T2.query(q[i].ai - 1);
    	}
    	for(int i = 1;i <= m;++i) printf("%d %d
    ",ans1[i],ans2[i]); 
        return 0;   
    }
    
  • 相关阅读:
    (React 框架)React技术
    React 项目
    JS语法之--模块化
    JS 语法之-- 解构,Promise(异步)
    JS 语法之--对象类型(构造器,class,this),高阶对象(高阶类,Minix模式)
    javascript:console对象与控制台
    javascript:错误处理
    javascript:基本数据类型转换
    javascript:数据结构-数组
    javascript:数据结构-对象
  • 原文地址:https://www.cnblogs.com/wyxdrqc/p/10982394.html
Copyright © 2011-2022 走看看