「bzoj3956: Count」

Posted asuldb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「bzoj3956: Count」相关的知识,希望对你有一定的参考价值。

题目

刚开始并没有看懂题意于是痛苦的挣扎了好久

题意是这样的

([l,r])有多少对((i,j))满足(a_i)(a_j)恰好是(a_i...a_j)中严格最大的两个数

强制在线

先考虑(a_j)(a_i...a_j)严格第二大的那一个

我们可以一个单调栈扫过去找到(j)之前第一个大于等于(a_j)的,这个位置就是我们要找的(i)

再考虑(a_j)(a_i...a_j)最大的那一个

显然如果(i)满足(i<j)(a_j)(a_i)右边第一个满足(a_j>=a_i)的元素就好了

这样的话最终答案显然是(n)级别的,不会太大,于是直接用单调栈把这些区间都找出来,每次询问([l,r])完全包含了多个这样的区间就好了

主席树就可以实现

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<set>
#define mp std::make_pair
#define maxn 300005
#define M maxn*42
#define lowbit(x) ((x)&(-x))
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
    char c=getchar();int x=0;while(c<‘0‘||c>‘9‘) c=getchar();
    while(c>=‘0‘&&c<=‘9‘) x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
typedef std::pair<int,int> pii;
std::set<pii> s;
int n,m,q,cnt;
int st[maxn],top,last,rt[maxn];
int a[maxn],L[maxn],R[maxn];
std::vector<int> v[maxn];
int l[M],r[M],d[M];
int change(int pre,int x,int y,int pos)
{
    int root=++cnt;
    d[root]=d[pre]+1;
    if(x==y) return root;
    l[root]=l[pre],r[root]=r[pre];
    int mid=x+y>>1;
    if(pos<=mid) l[root]=change(l[pre],x,mid,pos);
        else r[root]=change(r[pre],mid+1,y,pos);
    return root;
}
int query(int p1,int p2,int x,int y,int k)
{
    if(x==y) return d[p2]-d[p1];
    int mid=x+y>>1;
    if(k<=mid) return query(l[p1],l[p2],x,mid,k)+d[r[p2]]-d[r[p1]];
    return query(r[p1],r[p2],mid+1,y,k);
}
int main()
{
    n=read(),m=read(),q=read();
    for(re int i=1;i<=n;i++) a[i]=read();
    for(re int i=n;i;--i)
    {
        while(top&&a[st[top]]<=a[i]) L[st[top--]]=i;
        st[++top]=i; 
    }
    top=0;
    for(re int i=1;i<=n;i++)
    {
        while(top&&a[st[top]]<=a[i]) R[st[top--]]=i;
        st[++top]=i;
    }
    for(re int i=1;i<=n;i++) if(L[i]) s.insert(mp(L[i],i));
    for(re int i=1;i<=n;i++) if(R[i]) s.insert(mp(i,R[i]));
    for(std::set<pii>::iterator i=s.begin();i!=s.end();++i)
    {
        pii t=*i;
        v[t.second].push_back(t.first);
    }
    for(re int i=1;i<=n;i++)
    {
        int now=rt[i-1];
        for(re int j=0;j<v[i].size();j++) now=change(now,1,n,v[i][j]);
        rt[i]=now;
    }
    int x,y;
    while(m--)
    {
        x=read(),y=read();
        if(q) x=(x+last-1)%n,y=(y+last-1)%n,x++,y++;
        if(x>y) std::swap(x,y);
        if(x==y) last=0;
        else last=query(rt[x-1],rt[y],1,n,x);
        printf("%d
",last);
    }
    return 0;
}

以上是关于「bzoj3956: Count」的主要内容,如果未能解决你的问题,请参考以下文章

二维数点 bzoj 3956 Count

「bzoj3956: Count」

bzoj3956Count 单调栈+可持久化线段树

BZOJ1452: [JSOI2009]Count

BZOJ1833: [ZJOI2010]count 数字计数 (数位dp)

搜索棋盘 luogu-3956