首页 > 其他分享 >[luogu p8251] [NOI Online 2022 提高组] 丹钓战

[luogu p8251] [NOI Online 2022 提高组] 丹钓战

时间:2022-09-27 09:55:32浏览次数:86  
标签:nxt ch 二元 int luogu 09 丹钓战 2022 NOI

[P8251 NOI Online 2022 提高组] 丹钓战 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

容易发现对于一次查询 \([L, R]\),\(L\) 一定是第一个入栈的,也是成功的,答案至少为 \(1\);

那么下一个成功的二元组是多少呢?

每一个二元组入栈时有可能会把栈里某个二元组弹出去;

目前栈底是 \(L\),那下一个成功的就应该是把 \(L\) 弹出去然后自己进栈的那个二元组了,然后显然这个二元组之前都在 \(L\) 的上面所以都不成功;

也就是说下一个二元组应该是从 \(L\) 往后依次进栈,把 \(L\) 弹出的那个二元组,我们记作 \(nxt[L]\);

那么再下一个成功的二元组是多少呢?就是弹出 \(nxt[L]\) 的二元组,也就是 \(nxt[nxt[L]]\);

可以很轻松证明一次查询里,有且只有 \(L, nxt[L], nxt[nxt[L]], nxt[nxt[nxt[L]]], \cdots\)(不超过 \(R\))是成功的;

考虑求解 \(nxt\) 数组,按题意从第一个二元组模拟到第 \(n\) 个求解就行了,复杂度 \(\mathcal{O}(n)\);

但是单次回答询问 \(\mathcal{O}(n)\) 无法承受;

很容易想到 \(L, nxt[L], nxt[nxt[L]], nxt[nxt[nxt[L]]], \cdots\) 可以非常裸地套用倍增优化;

\(nxt[i][j]\) 表示第 \(i\) 个二元组往后跳第 \(2^j\) 个成功二元组是多少,这个 \(\mathcal{O}(n\log n)\) 预处理好;

然后回答 \(\mathcal{O}(\log n)\) 跳就可以了。这题就做完了。

想一想,大概本题思维重点是对于任何一个区间 \([L, R]\) 上考虑,由于入栈顺序的确定性,\(nxt[i]\) 的定义、值也是确定的。所以求解 \(nxt\) 数组直接整体跑一遍然后应用在每一个区间上,达到加速目的。

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2022-09-27 09:21:24 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2022-09-27 09:45:09
 */
#include <bits/stdc++.h>
inline int read() {
    int x = 0;
    bool flag = true;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-')
            flag = false;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }
    if(flag)
        return x;
    return ~(x - 1);
}

const int maxn = (int)5e5 + 5;
const int lgn = 20;

int a[maxn], b[maxn], nxt[maxn][lgn];

int main() {
    int n = read(), q = read();
    for (int i = 1; i <= n; ++i)
        a[i] = read();
    for (int i = 1; i <= n; ++i)
        b[i] = read();
    
    std :: stack <int> s;
    for (int i = 1; i <= n; ++i) {
        while (!s.empty()) {
            int x = s.top();
            if (a[i] == a[x] || b[i] >= b[x]) {
                nxt[x][0] = i;
                s.pop();
            } else
                break;
        }
        s.push(i);
    }
    
    while (!s.empty()) {
        int x = s.top();
        nxt[x][0] = n + 1;
        s.pop();
    }

    nxt[n + 1][0] = n + 1;
    
    for (int d = 1; d < lgn; ++d)
        for (int i = 1; i <= n + 1; ++i)
            nxt[i][d] = nxt[nxt[i][d - 1]][d - 1];
    
    while (q--) {
        int l = read(), r = read();
        int ans = 1;
        for (int d = lgn - 1; d >= 0; --d) {
            if (nxt[l][d] <= r) {
                ans += 1 << d;
                l = nxt[l][d];
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}

标签:nxt,ch,二元,int,luogu,09,丹钓战,2022,NOI
From: https://www.cnblogs.com/crab-in-the-northeast/p/luogu-p8251.html

相关文章

  • luogu P1052 [NOIP2005 提高组] 过河
    [NOIP2005提高组]过河题目描述在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳......
  • 做题记录整理dp12 P7961 [NOIP2021] 数列(2022/9/26)
    P7961[NOIP2021]数列当时在考场上对于拿部分分这个感念不是很清晰,所以当时连暴力分都没拿。。。事实上这题在看了题解之后还是有很多地方没搞明白,比如最后统计答案,为什......
  • luogu P2233 [HNOI2002]公交车路线
    [HNOI2002]公交车路线题目描述在长沙城新建的环城公路上一共有\(8\)个公交站,分别为A、B、C、D、E、F、G、H。公共汽车只能够在相邻的两个公交站之间运行,因此你从某一......
  • P6835 [Cnoi2020]线形生物 题解
    通过这道题可以看出来pz根本不会期望考虑期望线性性质,设\(E_{x\toy}\)表示从\(x\)走到\(y\)的期望步数,那么有\(E_{1\ton+1}=\sum_{i=1}^nE_{i\toi+1}\),因此考......
  • luogu P1772 [ZJOI2006] 物流运输 (dp, 最短路)
    https://www.luogu.com.cn/problem/P1772虽然是图论背景,但是1-n天之间是线性关系。没法贪心决策,考虑dp:我本来写的dp是i-1转移到i,但是这样没法处理哪一天能走哪些最短路......
  • luogu P1410 子序列
    子序列题目描述给定一个长度为\(N\)(\(N\)为偶数)的序列,问能否将其划分为两个长度为\(N/2\)的严格递增子序列。输入格式若干行,每行表示一组数据。对于每组数据,首......
  • 【luogu P4218】珠宝商(SAM)(点分治)(根号分治)
    珠宝商题目链接:luoguP4218题目大意给你一棵树,每个点有一个字符。再给你一个字符串s。然后问你树上的所有简单的路径在s上的出现次数的和。思路一个比较神奇的题......
  • 【补题计划】NOI Online 2022
    【NOIOnline2022】补题记录入门组T1[NOIOnline2022]王国比赛lj小模拟一遍过(都没编译就交了)点击查看代码#include<iostream>#include<cstdio>#include<cmath>......
  • luogu P7632 题解
    一.思路我们可以先把时间换成以秒为单位的,然后在枚举每一秒时谁领先。二.重要点我们可以用string读入时间,再用一个函数以秒为单位提取出来(在程序中的函数名:tiqu)......
  • NOIP2018 day1 题解
    心血来潮看了看18年的联赛,感觉自己进步很大==T1对于一个“波”来说,显然需要的次数为最大的数(波峰),对于多个“波”,就每次记录一下从波底到波峰的高度差即可,这可以用差分简......