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

 

posted @ 2016-08-09 21:10  DaD3zZ  阅读(660)  评论(0编辑  收藏  举报