[BZOJ3956]Count(单调栈+线段树)题解
Count

输入
3 2 0
2 1 2
1 1
1 3
输出
0
3
分析
- 好点的配对使用单调栈预处理
处理:
当进栈的x大于栈顶元素,弹栈并对x统计好点数
当进栈的x等于栈顶元素,弹栈(因相等所以无法向前配对)
当进栈的x小于栈顶元素,入栈(和之后的元素配对) - 对于lc[i] 指1~i中配对的个数且进行前缀和处理
- 对于rc[i] 指i~n中配对的个数且进行后缀和处理
- 对于区间[l,r],用线段树查找最大权值的下标k
l~k-1中没有可以和k之后的点配对
k+1~r中没有可以和k之前的点配对 - 对于[l,r]的答案即为[l,k]中的好点对数+[k,r]中的好点对数
即lc[r]-lc[k]+rc[l]-rc[k];
代码
#include<bits/stdc++.h>
using namespace std;
#define ls (ro<<1)
#define rs (ro<<1|1)
struct jade
{
int l,r,num;
}t[1200010];
int a[300005],st_ack[300005],lc[300005],rc[300005];
void pushup(int ro)
{
if(a[t[ls].num]<a[t[rs].num])
{
t[ro].num=t[rs].num;
}
else
{
t[ro].num=t[ls].num;
}
}
void build(int ro,int l,int r)
{
t[ro].l=l;
t[ro].r=r;
if(l==r)
{
t[ro].num=l;
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(ro);
}
int find(int ro,int l,int r)
{
if(l<=t[ro].l&&r>=t[ro].r)
{
return t[ro].num;
}
int mid=(t[ro].l+t[ro].r)>>1;
int x=0;
if(l<=mid)
{
int ll=find(ls,l,r);
if(a[ll]>=a[x])
{
x=ll;
}
}
if(r>mid)
{
int rr=find(rs,l,r);
if(a[rr]>a[x])
{
x=rr;
}
}
return x;
}
int main()
{
int n,q,ty;
cin>>n>>q>>ty;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int top=0;
for(int i=1;i<=n;i++)
{
while(top)
{
lc[i]++;
if(a[st_ack[top]]>=a[i])
{
break;
}
top--;
}
while(top)
{
if(a[st_ack[top]]>a[i])
{
break;
}
top--;
}
top++;
st_ack[top]=i;
lc[i]+=lc[i-1];
}
top=0;
for(int i=n;i>=1;i--)
{
while(top)
{
rc[i]++;
if(a[st_ack[top]]>=a[i])
{
break;
}
top--;
}
while(top)
{
if(a[st_ack[top]]>a[i])
{
break;
}
top--;
}
top++;
st_ack[top]=i;
rc[i]+=rc[i+1];
}
build(1,1,n);
int ans=0;
while(q--)
{
int ll,rr;
cin>>ll>>rr;
int l=min((ll+ans-1)%n+1,(rr+ans-1)%n+1);
int r=max((ll+ans-1)%n+1,(rr+ans-1)%n+1);
if(ty)
{
ll=l;
rr=r;
}
int k=find(1,ll,rr);
ans=lc[rr]-lc[k]+rc[ll]-rc[k];
cout<<ans<<endl;
}
}
以下是签名
${\scr {jade }}$ ${\scr {seek }}$
本文来自博客园,作者:BIxuan—玉寻,转载请注明原文链接:https://www.cnblogs.com/zhangyuxun100219/p/18991212

浙公网安备 33010602011771号