【BZOJ3956】Count,单调栈+ST表维护区间最大值
2016-08-11 00:29
375 查看
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
其实也可以写主席树的,但我被相等情况的处理恶心到了,所以没有写下去……
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]); } }
其实也可以写主席树的,但我被相等情况的处理恶心到了,所以没有写下去……
相关文章推荐
- bzoj 3956: Count (单调栈+st表)
- 【BZOJ】3956 Count 单调栈+ST表
- Sliding Window(单调队列维护或线段树求区间最大最小值)
- [BZOJ3956]Count(单调栈+线段树)
- [BZOJ3956]Count(单调栈+线段树)
- 【BZOJ-3956】Count ST表 + 单调栈
- 【BZOJ3956】Count 主席树+单调栈
- hdu5289RMQ求区间最大最小值和单调队列维护区间最大最小值
- HUST1722(线段树维护区间最大连续和)
- 区间更新 区间和查询 带有延迟标记 线段树 hdu1698; 附:csa 区间加值,维护最大值
- [BZOJbegin][noip2016十连测第九场]小P的单调区间(dp+bit)
- bzoj 1012: [JSOI2008]最大数maxnumber(单调栈+二分)
- bzoj1012: [JSOI2008]最大数maxnumber[单调队列+二分]
- BZOJ 题目1036: [ZJOI2008]树的统计Count(Link Cut Tree,修改点权求两个最大值和最大值)
- HDU 4302 线段树单点更新,维护区间最大最小值
- bzoj 3064: Tyvj 1518 CPU监控 线段树维护历史最大值
- 无旋treap:从单点到区间(例题 BZOJ1500&NOI2005 维护数列 )
- 【bzoj4540】[Hnoi2016]序列 单调栈+离线+扫描线+树状数组区间修改区间查询
- HDU 3530 Subsequence(区间最值差>=m且<=k的最大长度、双单调队列)
- hdoj1754 I Hate It【线段树区间最大值维护+单点更新】