[bzoj3956]Count

3956: Count

Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 524 Solved: 214
[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

sol:
感觉自己果然还是弱爆了。这题直观上看好点对是不会有很多组的,具体怎么证我不知道。后来拿个单调递减的栈看了一下,显然top和top-1才会产生一个贡献,所以一个小的点最多只会和左边,右边比他大的点产生一次贡献,那最多是2n组。然后就只要求区间覆盖了。
然后我一开始的想法是预处理一下大力O1回答询问。所以往差分,把询问拆成l-1,r容斥之类的方向思考,结果好像都不能很好解决这个问题。因为我不知道怎么加加减减弄到那个区间内的答案。
后来一个julao告诉我直接主席树就能解决了,一个区间l,在l之后可以查询到r的话就能保证区间被覆盖了

#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
using namespace std;
int n,m;
inline int read()
{
    char c;
    int res,flag=0;
    while((c=getchar())>'9'||c<'0') if(c=='-')flag=1;
    res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0';
    return flag?-res:res;
}
const int N=310000;
const int M=12100000;
int type,last,l,r;
int sum[M],top,sta[N];
int a[N];
struct cc
{
    int x,y;
    inline friend bool operator <(const cc &a,const cc &b)
    {
        return a.x<b.x||a.x==b.x&&a.y<b.y;
    } 
}b[N*2];
int tot,nonsame,number;
int lc[M],rc[M];
inline void insert(int &x,int y,int l,int r,int pos)
{
    x=++number;
    sum[x]=sum[y]+1;
    lc[x]=lc[y];
    rc[x]=rc[y];
    if(l==r) return;
    int mid=l+r>>1;
    if(pos<=mid) insert(lc[x],lc[y],l,mid,pos);
    else insert(rc[x],rc[y],mid+1,r,pos);
}
inline int query(int x,int y,int l,int r,int L,int R)
{
    if(L<=l&&r<=R) return sum[x]-sum[y];
    int mid=l+r>>1,res=0;
    if(mid>=L) res+=query(lc[x],lc[y],l,mid,L,R);
    if(mid+1<=R) res+=query(rc[x],rc[y],mid+1,r,L,R);
    return res;
}
int rt[N],st;
int main()
{
//  freopen("3956.in","r",stdin);
//  freopen(".out","w",stdout);
    n=read();
    m=read();
    type=read();
    for(int i=1;i<=n;++i)
    {
        a[i]=read();
        nonsame=1;
        while(top>0&&a[i]>=a[sta[top]])
        {
            ++tot;
            b[tot].x=sta[top];
            b[tot].y=i;
            if(a[i]==a[sta[top]]) nonsame=0;
            --top;
        }
        sta[++top]=i;
        if(top>1&&nonsame)
        {
            ++tot;
            b[tot].x=sta[top-1];
            b[tot].y=i;
        }
    }
    sort(b+1,b+1+tot);
//  for(int i=1;i<=tot;++i)
//  printf("%d %d\n",b[i].x,b[i].y);
    st=1;
    for(int i=1;i<=n;++i)
    {
        rt[i]=rt[i-1];
        while(st<=tot&&b[st].x<=i)
        {
            insert(rt[i],rt[i],1,n,b[st].y);
            ++st;
        }
    }
    while(m--)
    {
        l=read();
        r=read();
        if(type)
        {
            l=(l+last-1)%n+1;
            r=(r+last-1)%n+1;
            if(l>r) swap(l,r);
        }
        printf("%d\n",last=query(rt[r],rt[l-1],1,n,l,r));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值