【BZOJ-3956】Count ST表 + 单调栈

3956: Count

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 173  Solved: 99
[Submit][Status][Discuss]

Description

Input

Output

Sample Input

3 2 0
2 1 2
1 1
1 3

Sample Output

0
3

HINT

M,N<=3*10^5,Ai<=10^9

Source

CH Round#64 MFOI杯水题欢乐赛day1 By Gromah

Solution

思路有了之后,比较好写的一道题

首先我们计算以每个点为区间左端的答案,以及区间右端的答案,利用单调栈可以$O(N)$的处理出来

同样可以预处理出它们的前缀和

然后我们考虑一次询问,假如我们得到$[l,r]$中的最大值位置mp

那么我们的答案,相当于是询问区间$[l,mp]$中所有点作为右端的答案与$[mp+1,r]$中所有点作为左端点的答案

那么显然前缀和计算就好,至于查询最大位置?线段树/ST表都可以处理

这里采用ST表,总复杂度是$O(NlogN+M)$

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}
    while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();}
    return x*f;
}
#define MAXN 300010
int N,M,T,h[MAXN]; long long last;
inline int GetL (int x,int y) {if (T) return min((x+last-1)%N,(y+last-1)%N)+1; else return min(x,y);}
inline int GetR (int x,int y) {if (T) return max((x+last-1)%N,(y+last-1)%N)+1; else return max(x,y);}
int log2[MAXN],dp[MAXN][21];
inline int MaxPos(int x,int y) {return h[x]>h[y]? x:y;}
void ST()
{
    log2[0]=-1;
    for (int i=1; i<=N; i++)
        if (i&(i-1)) log2[i]=log2[i-1];
            else log2[i]=log2[i-1]+1;
    for (int i=1; i<=N; i++) dp[i][0]=i;
    for (int j=1; (1<<j)<=N; j++)
        for (int i=1; i+(1<<j)-1<=N; i++)
            dp[i][j]=MaxPos(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
inline int RMQ(int l,int r)
{
    int tmp=log2[r-l+1];
    return MaxPos(dp[l][tmp],dp[r-(1<<tmp)+1][tmp]);
}
long long AnsL[MAXN],AnsR[MAXN];
int stack[MAXN],top;
void PreWork()
{
    top=0;
    stack[++top]=h[1];
    for (int i=2; i<=N; i++)
        {
            while (top && h[i]>stack[top]) AnsL[i]++,top--;
            if (top) AnsL[i]++;
            while (top && h[i]>=stack[top]) top--;
            stack[++top]=h[i];
        }
    top=0;
    stack[++top]=h[N];
    for (int i=N-1; i>=1; i--)
        {
            while (top && h[i]>stack[top]) AnsR[i]++,top--;
            if (top) AnsR[i]++;
            while (top && h[i]>=stack[top]) top--;
            stack[++top]=h[i];
        }
    for (int i=1; i<=N; i++) AnsL[i]+=AnsL[i-1],AnsR[i]+=AnsR[i-1];
    ST();
}
inline void Solve(int L,int R)
{
    int maxp=RMQ(L,R);
    printf("%lld\n",last=AnsR[maxp-1]-AnsR[L-1]+AnsL[R]-AnsL[maxp]);
}
int main()
{
    N=read(),M=read(),T=read();
    for (int i=1; i<=N; i++) h[i]=read();
    PreWork();
    while (M--)
        {
            int x=read(),y=read();
            int L=GetL(x,y),R=GetR(x,y);
            Solve(L,R);
        }
    return 0;
}
时间: 2024-08-07 00:16:05

【BZOJ-3956】Count ST表 + 单调栈的相关文章

[51nod 1288]汽油补给(ST表+单调栈)

[51nod 1288]汽油补给(ST表+单调栈) 题面 有(N+1)个城市,0是起点N是终点,开车从0 -> 1 - > 2...... -> N,车每走1个单位距离消耗1个单位的汽油,油箱的容量是T.给出每个城市到下一个城市的距离D,以及当地的油价P,求走完整个旅途最少的花费.如果无法从起点到达终点输出-1. 分析 贪心考虑,当我们到达一个城市x的时候,我们下一个到的城市应该是在x加满油的情况下,能到达的油价比x低的城市.如果每个加油城市之间的路都这样走,那么最后的价钱一定是最小的.

bzoj 3956: Count

3956: Count Description Input Output Sample Input 3 2 0 2 1 2 1 1 1 3 Sample Output 0 3 HINT M,N<=3*10^5,Ai<=10^9 Source CH Round#64 MFOI杯水题欢乐赛day1 By Gromah 题解: 性质很妙的一道题. 首先可以发现这个所有的点队数是很小的,考虑以把一个点作为两个端点中较小的一个,那么另一个端点肯定是向左向右第一个大于等于它的点,这是很显然的.... 我们

BZOJ 1012: [JSOI2008]最大数maxnumber 单调栈

单调栈 1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MB Submit: 4988  Solved: 2252 [Submit][Status][Discuss] Description 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度. 2. 插入操作.语法:A n 功能:将n加上t,其中

BZOJ 1057 ZJOI2007 棋盘制作 单调栈

题目大意:给定一个黑白两色的矩阵,求最大的黑白相间的子正方形和子矩阵 将奇数位置的点反色,然后就是求纯色的最大子正方形和子矩阵 将矩阵一层层剖分,每层上方是一段类似于▆▃▇▂▉的东西,用单调栈跑出每个点向左向右能拓展到的最大距离,更新答案即可 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 2020 using namespace

二维数点 bzoj 3956 Count

https://www.lydsy.com/JudgeOnline/problem.php?id=3956 70分好像可以莫队 首先要发现答案是\(\mathcal O(n)\)的 Proof: 考虑一个点\(a_k\)对区间\([l,r]\)的贡献 当且仅当\(a_k=max(a_{l+1}, ... , a_{r-1})\)且\(a_l>a_k\), \(a_k<a_r\) 于是对于一个点预处理一下\((x, y)\)左边比他大的\(x\), 右边比他大的\(y\) 重复的数字的话 答案就

BZOJ 3230 相似子串 | 后缀数组 二分 ST表

BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过的,也就是考虑左端点在i.右端点在什么范围内时这个子串没有出现过--答案是右端点在[i + height[i] - 1, n]范围内时这个子串没出现过,即右端点在没有被"i与排在前一个的后缀的公共前缀"覆盖的部分时,这个子串没有出现过. 那么我们记录以每个i开头的新子串的数量,求前缀和,然

HDU 4123 Bob&#39;s Race:单调队列 + st表

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4123 题意: 给你一棵树,n个节点,每条边有长度. 然后有m个询问,每个询问给定一个q值. 设dis[i]为:从节点i出发,不重复经过节点,所能够走的最远距离. 每次询问问你:区间[l,r]最长能有多长,同时保证 max{dis[i]} - min{dis[i]} <= q (i∈[l,r]) 题解: 首先有一个结论: 从树上的任意一个节点出发,尽可能往远走,最终一定会到达树的直径的两个端点之一.

bzoj 3238 [Ahoi2013]差异 后缀数组 + 单调栈

题目链接 Description 一个长度为\(n\)的字符串\(S\),令\(T_i\)表示它从第\(i\)个字符开始的后缀.求\[\sum_{1\leq i\leq j\leq n}len(T_i)+len(T_j)-2*lcp(T_i,T_j)\]其中,\(len(a)\)表示字符串\(a\)的长度,\(lcp(a,b)\)表示字符串\(a\)和字符串\(b\)的最长公共前缀. \(2\leq n\leq 500000\) 思路 \(O(n^2)\)枚举显然是不可行的,应从 贡献 的角度取

POJ1821 单调队列//ST表 优化dp

http://poj.org/problem?id=1821 当我们在考虑内层循环j以及决策k的时候,我们可以把外层变量i看作定值,以此来优化dp状态转移方程. 题意 有n个工人准备铺m个连续的墙,每个工人有他必须图的一面墙壁Si,最多连续铺Li,每铺一个就花费Ci的钱,问最多要多少钱: 朴素算法很好想,就dp[i][j]维护i工人到这j层墙壁的最大值,对于每个工人去枚举他涂墙壁的开头和结尾然后更新即可. 时间复杂度O(NMM) M的范围是16000,很显然会T,我们考虑状态转移方程. 对于每个