BZOJ 3956: Count 主席树 可持久化线段树 单调栈
https://www.lydsy.com/JudgeOnline/problem.php?id=3956
从描述可以得到性质: 每个好点对 ( 除了差值为1的好点对 ) 中间的数 ( i , j ) 一定有一个最大值, 视这个值控制这个好点对, 那么每个值最多只控制一个好点对.
然后我们就可以通过单调栈 ( 求出lp[i]左边第一个大于i的数的坐标, rp[i]右边第一个大于i的数的坐标, lf[i]左边第一个大于等于i的数的坐标 (为避免重复只统计有重复区间的值里的最左边一个,即lp=lf则不统计) ) 找到每个点控制的好点对 ( 也就是找到所有好点对 ) .
然后用主席树维护询问(对每个l建r作为查找值的树).
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 const int maxn=300010; 8 int n,m,T; 9 int a[maxn]={},sta[maxn]={},tail=0; 10 int lp[maxn]={},rp[maxn]={},lf[maxn]={},rt[maxn]={}; 11 int lc[maxn*40]={},rc[maxn*40]={},siz[maxn*40]={},tot=0; 12 struct nod{ 13 int x,y; 14 }e[maxn];int cnt=0; 15 bool mcmp(nod aa,nod bb){ return aa.x<bb.x; } 16 int read(){ 17 int w=0,f=1;char ch=getchar(); 18 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 19 while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();} 20 return w*f; 21 } 22 void build(int &x,int y,int l,int r,int z){ 23 x=++tot;siz[x]=siz[y]+1;lc[x]=lc[y];rc[x]=rc[y]; 24 if(l==r)return; 25 int mid=(l+r)/2; 26 if(z<=mid)build(lc[x],lc[y],l,mid,z); 27 else build(rc[x],rc[y],mid+1,r,z); 28 } 29 int getsum(int x,int y,int l,int r,int z,int t){ 30 if(z<=l&&r<=t)return siz[y]-siz[x]; 31 int mid=(l+r)/2,ans=0; 32 if(z<=mid)ans=getsum(lc[x],lc[y],l,mid,z,t); 33 if(t>mid)ans+=getsum(rc[x],rc[y],mid+1,r,z,t); 34 return ans; 35 } 36 inline void fir(){ 37 int i; 38 a[0]=a[n+1]=(1<<30); 39 for(i=1;i<=n;++i){ 40 while(a[sta[tail]]<=a[i])tail--; 41 lp[i]=sta[tail];sta[++tail]=i; 42 } 43 sta[0]=n+1;tail=0; 44 for(i=n;i>0;--i){ 45 while(a[sta[tail]]<=a[i])tail--; 46 rp[i]=sta[tail];sta[++tail]=i; 47 } 48 tail=0;sta[0]=0; 49 for(i=1;i<=n;++i){ 50 while(a[sta[tail]]<a[i])tail--; 51 lf[i]=sta[tail];sta[++tail]=i; 52 } 53 } 54 inline void init(){ 55 int i,j; 56 for(i=1;i<=n;++i){ 57 if(lp[i]&&rp[i]<=n&&lp[i]==lf[i]){//最近的比a[i]大的数与a[i]间没有与a[i]相等的数,避免重复记录 58 e[++cnt].x=lp[i];e[cnt].y=rp[i];//lp[i]和rp[i]必须合法 59 } 60 }sort(e+1,e+cnt+1,mcmp); 61 for(i=j=1;i<=n;++i){ 62 rt[i]=rt[i-1]; 63 while(j<=cnt&&e[j].x==i){build(rt[i],rt[i],1,n,e[j].y);j++;} 64 } 65 } 66 int main(){ 67 int i,x,y,ans=0; 68 n=read();m=read();T=read(); 69 for(i=1;i<=n;++i)a[i]=read(); 70 fir(); init(); 71 for(i=1;i<=m;++i){ 72 x=read();y=read(); 73 if(T){x=(x+ans-1)%n+1;y=(y+ans-1)%n+1;} 74 if(x>y)swap(x,y); 75 ans=getsum(rt[x-1],rt[y],1,n,x,y)+y-x; 76 printf("%d\n",ans); 77 } 78 return 0; 79 }