• Nowcoder little w and Discretization 主席树/线段树+树状数组/分块莫队


    题目大意

    给定一个序列,求区间中大于mex的数有多少

    \(n \leq 3 \times 10^5\)

    思路一 主席树

    考虑区间mex,本题中不考虑0,区间mex的取值范围为\([a_i,a_i + 1]\)

    首先考虑区间mex求法,记\(end_i\)表示合并后第\(i\)个数的最后出现位置,对于一个区间\([l,r]\),合并后就相当于在第\(r\)棵树上找第一个出现位置\(pos < l\)的数。

    答案即为:\(len - cnt_{min_sq,mex}\)

    代码一 主席树

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2e6 + 10;
    int pre[N][2];
    int n;
    int c[N];
    int a[N];
    int l,r;
    int m;
    int ans[N];
    struct node {
    	int id;
    	int pos;
    	node (int _id,int _pos) {
    		id = _id;
    		pos = _pos;
    	}
    };
    
    vector <node> q[N];
    int lowbit(int x) {
    	return x & -x;
    }
    
    void modify(int x,int v) {
    	while(x <= n) {
    		c[x] += v;
    		x += lowbit(x);
    	}
    }
    
    int query(int x) {
    	int ans = 0;
    	while(x) {
    		ans += c[x];
    		x -= lowbit(x);
    	}
    	return ans;
    }
    int t;
    int main () {
    	cin >> n >> t >> m;
    	for(int i = 1;i <= n; i ++) scanf("%d",&a[i]);
    	for(int i = 1;i <= m; i ++) {
    		scanf("%d %d",&l,&r);
    		q[r].push_back(node(i,l));
    	}
    	for(int i = 1;i <= n; i ++) {
    		if(pre[a[i]][1]) {
    			modify(pre[a[i]][1],-1);
    			modify(pre[a[i]][0],1);
    		}
    		else if(pre[a[i]][0]) {
    			modify(pre[a[i]][0],1);
    		}
    		pre[a[i]][1] = pre[a[i]][0];
    		pre[a[i]][0] = i;
            int len = q[i].size();
    		for(int j = 0;j < len; j ++) {
    			node y = q[i][j];
    			ans[y.id] = query(i) - query(y.pos - 1);
    		}
    	}
    	for(int i = 1;i <= m; i ++) {
    		printf("%d\n",ans[i]);
    	}
    	return 0;
    }
    

    思路二 离散+树状数组+线段树

    同思路一情况,离线处理即可。

    代码二

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 3e5 + 10;
    
    int t[N << 2];
    int c[N << 1];
    int n,m;
    int a[N];
    
    struct qy {
    	int l,r;
    	int mex;
    	int ansl;
    	int ansr;
    	int id;
    };
    
    bool cmp(qy a,qy b) {
    	return a.r < b.r;
    }
    
    bool cmp2 (qy a,qy b) {
    	return a.l < b.l;
    }
    
    bool cmp3(qy a,qy b) {
    	return a.id < b.id;
    }
    qy q[N << 1];
    
    void update(int l,int r,int rt,int pos,int v) {
    	if(l == r) {
    		t[rt] = v;
    	}
    	else {
    		int mid = (l + r) >> 1;
    		if(pos <= mid) {
    			update(l,mid,rt << 1,pos,v);
    		}
    		else {
    			update(mid + 1,r,rt << 1 | 1,pos,v);
    		}
    		t[rt] = min(t[rt << 1],t[rt << 1 | 1]);
    	}
    }
    
    int query(int l,int r,int rt,int pos) {
    	if(l == r) return l;
    	int mid = (l + r) >> 1;
    	int ch = rt << 1;
    	if(t[ch] < pos) {
    		return query(l,mid,ch,pos);
    	}
    	else return query(mid + 1,r,ch + 1,pos);
    }
    
    int lowbit(int x) {
    	return x & -x;
    }
    
    void add(int pos,int v) {
    	while(pos <= n) {
    		c[pos] += v;
    		pos += lowbit(pos);
    	}
    }
    
    int getAns (int pos) {
    	int res = 0;
    	while(pos > 0) {
    		res += c[pos];
    		pos -= lowbit(pos);
    	}
    	return res;
    }
    
    int main () {
    	memset(t,-1,sizeof t);
    	cin >> n;
    	for (int i = 1;i <= n; i++) {
    		scanf("%d",&a[i]);
    	}
    	cin >> m;
    	for(int i = 1;i <= m; i ++) {
    		scanf("%d %d",&q[i].l,&q[i].r);
    		q[i].id = i;
    	}
    	sort(q + 1,q + m + 1,cmp);
    	for(int i = 1,pos = 1;i <= n; i ++) {
    		if(a[i] <= n) {
    			update(1,n + 1,1,a[i],i);
    			add(a[i],1);
    		}
    		for( ; q[pos].r == i and pos <= m;pos ++) {
    			q[pos].mex = query(1,n + 1,1,q[pos].l);
    			q[pos].ansr = getAns(q[pos].mex);
    		}
    	}
    	memset(c,0,sizeof c);
    
    	sort(q + 1,q + m + 1,cmp2);
    
    	for (int i = 0,pos = 1;i <= n; i ++) {
    		if(i and a[i] <= n) {
    			add(a[i],1);
    		}
    		for( ; q[pos].l - 1== i and pos <= m;pos ++) {
    			q[pos].ansl = getAns(q[pos].mex);
    		}
    	}
    
    
    	sort(q + 1,q + m + 1,cmp3);
    
    	for(int i = 1;i <= m; i ++) {
    		printf("%d\n",q[i].r - q[i].l + 1 - q[i].ansr + q[i].ansl);
    	}
    	return 0;
    }
    

    思路三 分块+莫队

    这个题感觉莫队可能更好玩一点,比较套路。

    代码三 区间mex

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 3e5 + 10;
    const int K = 548;
    
    int belone[N];
    int block;
    int B[K + 1];
    int a[N];
    int n,m;
    int ans[N];
    int cnt[N];
    
    struct node {
    	int l,r;
    	int id;
    }q[N];
    
    int get (int x) {
    	return (x - 1) / block + 1;
    }
    
    bool cmp(node a,node b) {
        if(belone[a.l] == belone[b.l]) return a.r < b.r;
        else return belone[a.l] < belone[b.l];
    }
    
    void add(int x) {
    	if(++cnt[x] == 1) B[x / K] ++;
    }
    
    void del(int x) {
    	if(--cnt[x] == 0) B[x / K] --;
    }
    
    int query(int x) {
    	for(int i = 1;i <= K;i ++) {
    		if(B[i - 1] != K) {
    			for(int j = (i - 1) * K;j < K * i;j ++) {
    				if(cnt[j] == 0) {
    					return j;
    				}
    			}
    		}
    	}
    }
    int main () {
    	scanf("%d %d",&n,&m);
    	block = sqrt(n);
    	for (int i = 1;i <= n; i ++) {
    		int x;
    		scanf("%d",&x);
    		a[i] = min(n + 1,x);
    		belone[i] = get(i);
    	}
    	for(int i = 1;i <= m; i ++) {
    		int l,r;
    		scanf("%d %d",&l,&r);
    		q[i] = node{l,r,i};
    	}
    	sort(q + 1,q + m + 1,cmp);
    	int l = 1;
    	int r = 0;
    	for(int i = 1;i <= m; i ++) {
    		while(l < q[i].l) del(a[l ++]);
    		while(l > q[i].l) add(a[-- l]);
    		while(r < q[i].r) add(a[++ r]);
    		while(r > q[i].r) del(a[r --]);
    		ans[q[i].id] = query(i);
    	}
    	for(int i = 1;i <= m; i ++) {
    		printf("%d\n",ans[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    axios
    MySQL -- 书写规则(常数:字符串、日期、数字、 单引号的使用、半角空格)
    MySQL -- 图解:内连接、外连接、左(外)连接、右(外)连接、全连接
    Linux -- Linux下md5sum用法 (查看文件或字符串的md5值)
    Python3 -- Python获取昨天,今天,明天,本周,上周,本月,上月,本季,本年,去年时间
    Linux -- 执行脚本时&和&&
    Linux -- 定时任务 crontab 命令
    Python3 -- json格式 存储、读取文件
    Hive -- SQL 语法
    Hive -- 目录
  • 原文地址:https://www.cnblogs.com/Allorkiya/p/15902095.html
Copyright © 2020-2023  润新知