题目大意
给定一个序列,求区间中大于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;
}