【BZOJ3956】Count,单调栈+ST表维护区间最大值

Time:2016.08.11
Author:xiaoyimi
转载注明出处谢谢


传送门
思路:
TA爷眼中的水题
首先有个特别的结论
总共的点对数不会超过2n
因为对于元素i来说,如果只考虑与比它高的元素进行配对
那么最多左边一个,右边一个,再靠左或靠右的就不满足配对条件了
考试的时候我想到的是单调栈维护一个不上升的序列,但不知道具体并不会做
讲题时使用了ST表维护区间最大
(为什么不用线段树?因为线段树常数比较大……而且这里是静态查询,正好是RMQ经典操作)
考虑区间[l,r]
找出[l,r]中最大高度的下标k
显然l~k-1不能和k之后的元素配对
k+1~r不能和k之前的元素配对
ans=[l,k]在[l,k]中的配对个数+[k,r]在[k,r]中的配对个数
这个是可以前缀和维护的
前后各扫一遍
f[i]指i在[1,i]中配对数量
g[i]指i在[i,n]中配对数量
sum1[i]=Σf[j] 1<=j<=i
sum2[i]=Σg[j] i<=j<=n
ans=sum1[r]-sum1[k]+sum[l]-sum2[k]
注意高度相等时的处理,这里很恶心,我就不细说了ORZ

#include<cstdio>
#include<iostream>
#include<cmath> 
#define M 300003
#define pd(x,y) (a[x]>a[y]?x:y)
using namespace std;
int in()
{
    int t=0;char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar();
    return t;
}
int n=in(),m=in(),tp=in();
int sum1[M],sum2[M],S[M];
int a[M],fa[M][19];
int RMQ(int x,int y)
{
    int t=log2(y-x+1);
    return pd(fa[x][t],fa[y-(1<<t)+1][t]);
}
main()
{
    for (int i=1;i<=n;i++) a[i]=in();
    for (int i=1;i<=n;i++)
    {
        for (;S[0];S[0]--)
        {
            sum1[i]++;
            if (a[S[S[0]]]>=a[i]) break;
        }
        for (;S[0];S[0]--)
            if (a[S[S[0]]]>a[i]) break;
        S[++S[0]]=i;
        sum1[i]+=sum1[i-1];
    }
    S[0]=0;
    for (int i=n;i>=1;i--)
    {
        for (;S[0];S[0]--)
        {
            sum2[i]++;
            if (a[S[S[0]]]>=a[i]) break;
        }
        for (;S[0];S[0]--)
            if (a[S[S[0]]]>a[i]) break;
        S[++S[0]]=i;
        sum2[i]+=sum2[i+1];
    }
    for (int i=1;i<=n;i++) fa[i][0]=i;
    for (int i=1;(1<<i)<=n;i++)
        for (int j=1;j+(1<<i)-1<=n;j++)
            fa[j][i]=pd(fa[j][i-1],fa[j+(1<<i-1)][i-1]);
    int mx,l,r,L,R,lastans=0;
    for (;m;m--)
    {
        l=in();r=in();
        if (tp)
            L=min((lastans+l-1)%n,(lastans+r-1)%n)+1,
            R=max((l+lastans-1)%n,(r+lastans-1)%n)+1;
        else L=l,R=r;
        mx=RMQ(L,R);
        printf("%d\n",lastans=sum1[R]-sum1[mx]-sum2[mx]+sum2[L]);
    }
}

其实也可以写主席树的,但我被相等情况的处理恶心到了,所以没有写下去……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值