bzoj 3956: Count

发现好点对互不跨立,所以只有O(n)个,用单调队列找出这O(n)个然后用主席树维护就可以了。
对于a[i]相等的情况的单调队列写错了一些细节。
   
   
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
 
#define ll long long
#define inf 1e9
#define eps 1e-8
#define md
#define N 300010
#define TR 12000010
using namespace std;
struct QQ { int h,id;} q[N];
struct PP { int x,y;} p[2*N];
int ch[TR][2],sz[TR],a[N],root[N];
int cnt;
bool cmp(PP a,PP b) { return a.x==b.x?a.y<b.y:a.x<b.x;}
 
void insert(int &i,int pre,int l,int r,int x)
{
i=++cnt; ch[i][0]=ch[pre][0]; ch[i][1]=ch[pre][1]; sz[i]=sz[pre]+1;
if (l==r) return;
int mid=(l+r)>>1;
if (x<=mid) insert(ch[i][0],ch[pre][0],l,mid,x);
else insert(ch[i][1],ch[pre][1],mid+1,r,x);
}
 
int query(int a,int b,int l,int r,int ql,int qr)
{
if (ql<=l&&r<=qr) return sz[b]-sz[a];
int mid=(l+r)>>1;
if (qr<=mid) return query(ch[a][0],ch[b][0],l,mid,ql,qr);
if (mid+1<=ql) return query(ch[a][1],ch[b][1],mid+1,r,ql,qr);
return query(ch[a][0],ch[b][0],l,mid,ql,qr)+query(ch[a][1],ch[b][1],mid+1,r,ql,qr);
}
 
int main()
{
int n,m,Ty;
scanf("%d%d%d",&n,&m,&Ty);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
int top=0,tot=0;
for (int i=1;i<=n;i++)
{
bool had=0;
while (top&&q[top].h<=a[i]) { p[++tot]=(PP){q[top].id,i}; if (q[top].h==a[i]) had=1; top--;}
if (top&&!had) p[++tot]=(PP){q[top].id,i};
q[++top]=(QQ){a[i],i};
}
sort(p+1,p+tot+1,cmp);
int now=0;
for (int i=1;i<=n;i++)
{
root[i]=root[i-1];
while (now<tot&&p[now+1].x==i) { now++; insert(root[i],root[i],1,n,p[now].y);}
}
int ans=0;
for (int i=1;i<=m;i++)
{
int l,r;
scanf("%d%d",&l,&r);
if (Ty) { l=(l+ans-1)%n+1; r=(r+ans-1)%n+1; if (l>r) swap(l,r); }
ans=query(root[l-1],root[r],1,n,l,r);
printf("%d\n",ans);
}
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值