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;
} 

时间: 2024-12-13 09:47:07

bzoj3339的相关文章

【bzoj3339】Rmq Problem

[bzoj3339]Rmq Problem Description Input Output Sample Input 7 50 2 1 0 1 3 21 32 31 43 62 7 Sample Output 30324 HINT 分析 离线算法. 对于[l,r]区间的询问,我们可以线性求出来,然后考虑[l+1,r]区间有什么不同,在a[l]下一次出现的位置之前,所有大于a[l]的mex,都变成是a[l],因为 [l+1,a[l]下一次出现的位置-1],这个区间内没有a[l]了,大于它的数当然

[BZOJ3585][BZOJ3339]mex

试题描述 有一个长度为n的数组{a1,a2,...,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. 输入 第一行n,m.第二行为n个数.从第三行开始,每行一个询问l,r. 输出 一行一个数,表示每个询问的答案. 输入示例 5 5 2 1 0 2 1 3 3 2 3 2 4 1 2 3 5 输出示例 1 2 3 0 3 数据规模及约定 对于100%的数据:1<=n,m<=2000000<=ai<=1091<=l<=r<=n 题解 首先离线,将询问按右端

bzoj3339 Rmq Problem

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3339 [题解] 业界偷懒. 突然发现好像可以主席树啊..然后就强行上了一波发现确实可以. 第i棵主席树维护[1...i]这个前缀内,某权值区间的"最小出现位置". 比如 2 3 0 1 那么在rt[4]这棵主席树中,[0,3]最小出现位置为1,是2在第1位:[0,1]最小出现位置为3,是0在第3位. 那么查询(x,y)我们查询rt[y]根据最小出现位置x来在主席树上二分走即可.

bzoj3339 rmq problem (range mex query)

给一个长度为n的数列a,q个询问,每次询问一段区间的mex.(没有出现过的最小非负整数) 1<=n,q<=200000,0<=ai<=200000. 题解1 莫队 我们将权值分成根号块,记录每个权值的出现次数和每块内有多少权值出现过. 修改和询问就直接暴力做就行. 修改O(1),询问O(sqrt(n)),加在一起还是O((n+q)sqrt(n+q)). #include <iostream> #include <stdio.h> #include <s

【莫队算法】【权值分块】bzoj3339 Rmq Problem

如题. #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define N 200001 #define BN 451 int n,m,a[N],b[N],sumv[BN],l[N],num[N],num2[N],Lim,siz[BN],anss[N]; struct Ask{int l,r,p;void Read(){scanf("%d%d",&am

BZOJ3339:Rmq Problem &amp; BZOJ3585 &amp; 洛谷4137:mex——题解

前者:https://www.lydsy.com/JudgeOnline/problem.php?id=3339 后者: https://www.lydsy.com/JudgeOnline/problem.php?id=3585 https://www.luogu.org/problemnew/show/P4137 有一个长度为n的数组{a1,a2,…,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. 题解大部分都是莫队分块,但是复杂度为O(n*sqrt(n))=5e2*2e5=1e

9.20 noip模拟试题

  Problem 1 双色球(ball.cpp/c/pas) [题目描述] 机房来了新一届的学弟学妹,邪恶的chenzeyu97发现一位学弟与他同名,于是他当起了善良的学长233 “来来来,学弟,我考你道水题检验一下你的水平……” 一个栈内初始有n个红色和蓝色的小球,请你按照以下规则进行操作 只要栈顶的小球是红色的,将其取出,直到栈顶的球是蓝色 然后将栈顶的蓝球变成红色 最后放入若干个蓝球直到栈中的球数为n 以上3步骤为一次操作 如栈中都是红色球,则操作停止,请问几次操作后停止 chenzey

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734

[转载]hzwer的bzoj题单

counter: 664BZOJ1601 BZOJ1003 BZOJ1002 BZOJ1192 BZOJ1303 BZOJ1270 BZOJ3039 BZOJ1191 BZOJ1059 BZOJ1202 BZOJ1051 BZOJ1001 BZOJ1588 BZOJ1208 BZOJ1491 BZOJ1084 BZOJ1295 BZOJ3109 BZOJ1085 BZOJ1041 BZOJ1087 BZOJ3038 BZOJ1821 BZOJ1076 BZOJ2321 BZOJ1934 BZOJ