bzoj3339

线段树+离线

这种题既可以用莫队做也可以用线段树做,跟hh的项链差不多

首先我们处里出前缀mex,也就是1->i的mex值,再预处理出每个数下一次出现的位置,然后把每个前缀mex插入线段树,每个节点表示l==r表示1->l的mex,然后把询问按左端点排序,依次查询,修改每次把小于当前左端点的数的影响去除,也就是把i->nxt[i-1]的mex和a[i]取min,因为这些前缀mex的a[i]消失了,那么取min就是新答案,每次查询就是单点查询,也就是查询1->r的前缀mex,因为1-l-1的影响都被消除了,所以现在1-r的答案就是l-r的答案

#include<bits/stdc++.h>
using namespace std;
const int N = 200010, inf = 0x3f3f3f3f;
struct query_ {
    int l, r, id;
    bool friend operator < (query_ A, query_ B)  {
        return A.l < B.l;
    }
} q[N];
int n, m;
int nxt[N], tree[N << 2], tag[N << 2], a[N], ans[N], vis[N], last[N];
void pushdown(int x)
{
    if(tag[x] == inf) return;
    tag[x << 1] = min(tag[x << 1], tag[x]);
    tag[x << 1 | 1] = min(tag[x << 1 | 1], tag[x]);
    tree[x << 1] = min(tree[x << 1], tag[x]);
    tree[x << 1 | 1] = min(tree[x << 1 | 1], tag[x]);
    tag[x] = inf;
} 
void update(int l, int r, int x, int a, int b, int mn)
{
    if(l > b || r < a) return;
    if(l >= a && r <= b)
    {
        tag[x] = min(tag[x], mn);
        tree[x] = min(tree[x], mn);
        return;
    }
    pushdown(x);
    int mid = (l + r) >> 1;
    update(l, mid, x << 1, a, b, mn);
    update(mid + 1, r, x << 1 | 1, a, b, mn);
    tree[x] = min(tree[x << 1], tree[x << 1 | 1]);
}
int query(int l, int r, int x, int pos)
{
    if(l == r) 
    {
//      printf("l = %d r = %d pos = %d tree[%d] = %d\n", l, r, pos, x, tree[x]);
        return tree[x]; 
    }
    pushdown(x);
    int mid = (l + r) >> 1;
    if(pos <= mid) return query(l, mid, x << 1, pos);
    else return query(mid + 1, r, x << 1 | 1, pos);
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    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);
    int pos = 0;
    memset(tree, 0x3f3f, sizeof(tree));
    memset(tag, 0x3f3f, sizeof(tag));
    for(int i = 1; i <= n; ++i)
    {
        nxt[last[a[i]]] = i;
        last[a[i]] = i;
        vis[a[i]] = 1;
        while(vis[pos]) ++pos;
//      printf("i = %d pos = %d\n", i, pos);
        update(1, n, 1, i, i, pos);
    }
    for(int i = 1; i <= n; ++i) if(nxt[i] == 0) nxt[i] = n + 1;
    pos = 1;
    for(int i = 1; i <= m; ++i)
    {
        while(pos < q[i].l && pos <= n) 
        {
            update(1, n, 1, pos, nxt[pos] - 1, a[pos]);
    //      printf("pos = %d nxt[%d] = %d a[%d] = %d\n", pos, pos, nxt[pos], pos, a[pos]);
            ++pos;
        }   
//      printf("q[%d].l = %d q[%d].r = %d id = %d pos = %d\n", i, q[i].l, i, q[i].r, q[i].id, pos);
        ans[q[i].id] = query(1, n, 1, q[i].r);      
    }
    for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
    return 0;
} 
View Code

 

posted @ 2017-09-01 12:18  19992147  阅读(187)  评论(0编辑  收藏  举报