laekov

BZOJ3585 mex

很久之前就看过的题。不过一直没有勇气去做。爱真的需要勇气。


mex这个函数的性质比较奇妙。一端确定的话一定是单增的。两段和起来也一定是增加的。


可以很方便地求出从1到任何一个位置的mex。考虑把询问离线。按左端点排序。如果去掉一个数,那么对于右端点在(从这个数到下一个等于这个数的位置)这一段里的询问,它的值至多是这个数。


所以用线段树维护区修单查维护一下区间最小值就好了。注意如果没有下一个数了那么右端点是n。


据说要离散不过被我用map给水过去了。


#include <cstdio>

#include <cctype>

#include <memory.h>

#include <map>

#include <algorithm>


using namespace std;


#define readInt(_s_) {\

int _d_;\

_s_ = 0;\

while (!isdigit(_d_ = getchar()));\

while ((_s_ = _s_ * 10 + _d_ - 48), isdigit(_d_ = getchar()));\

}


struct seg {

int l, r, z;

seg *ls, *rs;

};

struct query {

int l, r, n;

};


inline bool cmpQuery(const query& a, const query& b) {

return a. l < b. l;

}


typedef pair <int, int> rpair;


const int maxn = 200009;

const int inf = 0x3f3f3f3f;


int n, m, a[maxn], tmp[maxn], nv[maxn], m0[maxn], ans[maxn];

bool fv[maxn];

seg *rt, *sp;

query q[maxn];

map <int, int> rp;


inline bool cmpTmp(const int& x, const int& y) {

return (a[x] < a[y]) || (a[x] == a[y] && x < y);

}


#define mid(p) ((p->l+p->r)>>1)


seg* sgtBuild(int l, int r) {

seg* p = sp ++;

p-> l = l;

p-> r = r;

p-> z = inf;

if (l + 1 < r) {

p-> ls = sgtBuild(l, mid(p));

p-> rs = sgtBuild(mid(p), r);

}

else

p-> z = m0[l];

return p;

}


void sgtChg(seg* p, int l, int r, int v) {

if (p-> l == l && p-> r == r)

p-> z = min(p-> z, v);

else if (r <= mid(p))

sgtChg(p-> ls, l, r, v);

else if (l >= mid(p))

sgtChg(p-> rs, l, r, v);

else {

sgtChg(p-> ls, l, mid(p), v);

sgtChg(p-> rs, mid(p), r, v);

}

}


int sgtQry(seg* p, int p0) {

if (p-> l + 1 == p-> r)

return p-> z;

else if (p0 < mid(p))

return min(sgtQry(p-> ls, p0), p-> z);

else

return min(sgtQry(p-> rs, p0), p-> z);

}


void preSeq() {

a[0] = -1;

for (int i = 0; i <= n; ++ i)

tmp[i] = i;

sort(tmp, tmp + n + 1, cmpTmp);

m0[n] = 0;

for (int i = 0; i <= n; ++ i) {

if (a[tmp[i]] == m0[n])

++ m0[n];

if (i && a[tmp[i]] > a[tmp[i - 1]])

fv[tmp[i]] = 1;

else

fv[tmp[i]] = 0;

}

nv[n] = -1;

for (int i = n; i; -- i) {

if (!fv[i] || a[i] > m0[i])

m0[i - 1] = m0[i];

else

m0[i - 1] = a[i];

map <int, int> :: iterator it = rp. find(a[i]);

if (it == rp. end()) {

nv[i] = -1;

rp. insert(rpair(a[i], i));

}

else {

nv[i] = it-> second;

it-> second = i;

}

}

sp = new seg[maxn * 3];

rt = sgtBuild(1, n + 1);

}


void rmvNum(int i) {

if (nv[i] > -1)

sgtChg(rt, i, nv[i], a[i]);

else

sgtChg(rt, i, n + 1, a[i]);

}


int main() {

#ifndef ONLINE_JUDGE

freopen("in.txt", "r", stdin);

#endif


readInt(n);

readInt(m);

for (int i = 1; i <= n; ++ i)

readInt(a[i]);

for (int i = 0; i < m; ++ i) {

readInt(q[i]. l);

readInt(q[i]. r);

q[i]. n = i;

}

sort(q, q + m, cmpQuery);

preSeq();

for (int i = 0, j = 1; i < m; ++ i) {

for (; j < q[i]. l; ++ j)

rmvNum(j);

ans[q[i]. n] = sgtQry(rt, q[i]. r);

}

for (int i = 0; i < m; ++ i)

printf("%d\n", ans[i]);

}


评论

© laekov | Powered by LOFTER