3956: Count
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 177 Solved: 103
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
3 2 0
2 1 2
1 1
1 3
2 1 2
1 1
1 3
Sample Output
0
3
3
HINT
M,N<=3*10^5,Ai<=10^9
Source
题解:单调栈+st表
观察序列发现,只有形如^就是山峰型的序列两侧才会产生合法点对,而低谷型的可以跨越最低点形成合法点对,点对一定不会跨越最高点,所以我们可以维护一个单调递减的单调栈,如果当前元素大于栈顶元素,就出栈形成合法的点对,主要出栈时相邻元素也要形成合法点对,对于高度相等的情况需要特殊的记录和处理,具体见代码。
然后我们对于序列中的每一个位置分别维护点对左右端点的前缀和。对于一个区间的询问,我们用st表查询出区间的最大值的位置,然后统计最大值左边左端点的数量和最大值右边右端点的数量,就是答案。为什么?因为如果是合法点对那么就不可能跨越最高点,所以左右分别统计就好了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 1000003
using namespace std;
int n,m,h[N],st[N],suml[N],sumr[N];
int f[20][N],cnt,mark[N],l[N],type;
struct data
{
int x,y;
}point[N*2];
int cmp1(data a,data b)
{
return a.x<b.x;
}
int cmp2(data a,data b)
{
return a.y>b.y;
}
void solve()
{
for (int i=1;i<=n;i++) f[0][i]=i;
for (int i=1;i<=19;i++)
for (int j=1;j<=n;j++)
if (j+(1<<i)-1<=n)
{
int x=f[i-1][j];
int y=f[i-1][j+(1<<(i-1))];
if (h[x]<h[y])
f[i][j]=y;
else f[i][j]=x;
}
int j=0;
for (int i=1;i<=n;i++)
{
if ((1<<(j+1))<=i) j++;
l[i]=j;
}
}
int calc(int x,int y)
{
int k=l[y-x];
int a=f[k][x];
int b=f[k][y-(1<<k)+1];
if (h[a]<h[b]) return b;
else return a;
}
int main()
{
scanf("%d%d%d",&n,&m,&type);
for (int i=1;i<=n;i++) scanf("%d",&h[i]);
int top=1;
st[top]=1;
for (int i=2;i<=n;i++)
{
if (h[i]<h[st[top]])
{
++top;
st[top]=i;
}
else
{
while(h[st[top]]<=h[i]&&top)
{
++cnt;
point[cnt].x=st[top]; point[cnt].y=i;
if (h[st[top]]==h[i]&&top!=1) mark[i]=1;
if (top-1&&!mark[st[top]])
{
++cnt;
point[cnt].x=st[top-1]; point[cnt].y=st[top];
}
top--;
}
st[++top]=i;
}
}
for (int i=top;i>=2;i--)
if (!mark[st[i]])
{
++cnt;
point[cnt].x=st[i-1]; point[cnt].y=st[i];
}
sort(point+1,point+cnt+1,cmp1);
for (int i=1;i<=cnt;i++)
suml[point[i].x]++,sumr[point[i].y]++;
for (int i=1;i<=n;i++) suml[i]+=suml[i-1];
for (int i=1;i<=n;i++) sumr[i]+=sumr[i-1];
solve();
int lastans=0;
for (int i=1;i<=m;i++)
{
int l,r;
scanf("%d%d",&l,&r);
if (type) l=(l+lastans-1)%n+1,r=(r+lastans-1)%n+1;
if (l>r) swap(l,r);
int t=calc(l,r); //cout<<t<<endl;
lastans=suml[t-1]-suml[l-1]+sumr[r]-sumr[t];
printf("%d\n",lastans);
}
}