首页 > 其他分享 >P8251 [NOI Online 2022 提高组] 丹钓战 题解

P8251 [NOI Online 2022 提高组] 丹钓战 题解

时间:2022-10-20 22:03:22浏览次数:91  
标签:10 ch NOI int 题解 元素 丹钓战 && include

本文写于2022-03-26 14:45:14。原博客地址


题目链接

算法

(倍增) $O((n+q) \log n)$

为简便,把元素 $(a_i,b_i)$ 称为元素 $i$。

对一个区间 $[l,r]$ 模拟一遍,从空栈开始,头一个元素是“成功的”,然后堵在栈底直到被弹出,这期间入栈的元素不可能是“成功的”,弹出后栈又被清空,又回到了开头情况。所以答案就是整个过程中栈底元素的个数。因为任意元素只会被唯一元素弹出一次,所以可以从 $1$ 到 $n$ 模拟一遍,记 $s_i$ 会被 $s_{nxt_i}$ 弹出,复杂度为 $O(n)$ 。

求解过程转化成代码为:

int ans=1;	//首次入栈元素是“成功的”
for(int p=l;p<=r;p=nxt[p])  ans++;

可如果询问区间内每个 $nxt_i$ 都指向 $nxt_{i+1}$,那么相当于一步一弹,和暴力模拟没有区别。
定义 $f_{i,j}$ 为从元素 $i$ 开始弹 $2^j$次后的元素。若没有则为 $0$。在 $f$ 上面转移,一步弹2的幂次元素,就把询问优化到了 $O(\log n)$。$f$ 的预处理复杂度为 $O(n \log n)$。

思想:倍增。

C++ 代码

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;
//支持负数
template<typename T>
inline void read(T &x)
{
    char ch;bool flag = 0;
    while(!isdigit(ch=getchar()))
        (ch=='-')&&(flag=true);
    for(x=ch-'0';isdigit(ch=getchar());x=x*10+ch-'0');
    (flag)&&(x=-x);
}
template<typename T>
void print(T x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

typedef long long ll;
const int N=5e5+10,K=20;
int n,m,a[N],b[N],stk[N],tt,f[N][K];
inline bool check(int x,int y){return a[x]!=a[y]&&b[x]<b[y];}

int main()
{
    // freopen("stack.in","r",stdin);
    // freopen("stack.out","w",stdout);
    read(n),read(m);
    for(int i=1;i<=n;i++)   read(a[i]);
    for(int i=1;i<=n;i++)   read(b[i]);

	/init
    for(int i=1,tt=0;i<=n;i++)	//模拟,预处理f[i][0]
    {
        while(tt&&!check(i,stk[tt]))
            f[stk[tt--]][0]=i;
        stk[++tt]=i;
    }
    //元素i弹2^j次后的元素当然是
    //它弹2^(j-1)次后再弹2^(j-1)次后的元素
    for(int k=1;k<K;k++)	//从后往前转移f
        for(int i=n;i>=1;i--)
            f[i][k]=f[f[i][k-1]][k-1];

    //work
    for(int i=1,l,r;i<=m;i++)
    {
        read(l),read(r);int res=1; 
        for(int k=K-1;k>=0;k--)
            if(f[l][k]<=r&&f[l][k])	//注意要判f[l][k]!=0
            {
                res+=1<<k;
                l=f[l][k];	//一步弹2^k次
            }
        print(res),putchar('\n');
    }
    return 0;
}

标签:10,ch,NOI,int,题解,元素,丹钓战,&&,include
From: https://www.cnblogs.com/michaellee1112/p/16811472.html

相关文章

  • [NOIP2014 提高组] 联合权值 dfs+技巧
    题意树上每个结点的权值为\(w_i\),若点\(i\)和点\(j\)满足:\(i\)和\(j\)的最短距离为2,则会产生$w_i*w_j$的联合权值。求最大联合权值和联合权值之和。分析①最大联合......
  • wget --no-check-certificate 问题解决
    很多时候一些老旧机器因为ca证书的问题,造成下载异常,实际上解决方法很简单,一种方法是参考提示就行了解决方法添加--no-check-certificate使用.wgetrc文件(以后都就可......
  • AcCoders 10477:【省选基础数据结构 树链剖分】【GDOI2016】疯狂动物城 题解
    算法:树链剖分,可持久化线段树。题目大意给定\(n\)个结点的一棵树,\(m\)次操作,操作有三种:将\(x\)至\(y\)最短路径上的所有点的权值加上\(delta\)。对于\(x\)至......
  • 题解 For Problem. 完全参差序列
    Problem.完全参差序列题目背景2022年,南京师范大学迎来了120周年校庆,值此120周年校庆筹备工作全面启动之际,学校诚邀海内外校友、社会贤达、各界人士壬寅中秋相聚金陵,......
  • CF1742E Scuza题解
    CF1742EScuza题意简述\(t\)组数据,对于每组数据:有\(n\)级台阶,每级台阶比上一级高\(a_i\)米。有\(q\)次询问,每次询问给出一个腿长\(k\),问在每次跨上的高度不大......
  • 题解 P2224 [HNOI2001]产品加工
    一道很有趣的dp题。这道题是以答案为下标来设定状态,在这种生产问题这个套路还是挺常见的,需要积累一下。我们令\(f_{i,j}\)为前\(i\)个任务\(A\)机器花了\(j\)时......
  • 2017 ACM Arabella Collegiate Programming Contest div2的题,部分题目写个题解
    F.MonkeyingAround 维护点在多少个线段上​​http://codeforces.com/gym/101350/problem/F​​题意:有m个笑话,每个笑话的区间是[L,R],笑话种类有1e5,一开始所有猴子都在......
  • mysql函数 字符长度限制_MySQL中使用group_concat()函数数据字符过长报错的问题解决方
    selectGROUP_CONCAT(uid)asuids,spread_uidfromeb_user_spreadwhereuid<>spread_uidGROUPBYspread_uid使用GROUP_CONCAT函数将字符串连接起来,数据量大的时候,会......
  • CF 1012C. Hills 题解
    题目传送门:Link。算法:DP。设计状态第一眼看着道题就感觉像是DP,再观察数据范围大概是\(O(n^2)\)的时间复杂度。因为要求多个\(k\)的答案,那么状态第一维显然是令多......
  • 洛谷 P3224 [HNOI2012]永无乡 题解
    查询第\(k\)小值想到权值线段树。合并操作想到线段树合并。维护连通性想到并查集。并查集合并方向应与线段树合并方向一致。查询时,先求出并查集的根再在线段树上询......