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 }
View Code

 

 

posted @ 2018-04-10 17:31  鲸头鹳  阅读(139)  评论(0编辑  收藏  举报