博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

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;
}
posted @ 2022-02-16 19:53  Allorkiya  阅读(68)  评论(1编辑  收藏  举报