题目连接:Taotao Picks Apples
题意:给一个数列,然后替换掉一个数,求从左开始的严格递增序列长度(第一个必选)
题解:先预习处理前缀最大值和到这里的长度,在用单调栈处理出从i这里开始的递增序列长度。然后从n~1倒着建立主席树维护区间的最小下标。这样就可以询问后面开始的最小位置,对于每次询问反过来注意一下细节就可以了。
1 #include<bits/stdc++.h> 2 #define eps 1e-10; 3 using namespace std; 4 const int N = 1e5+7,M=6000005; 5 6 int h[N],n,m; 7 int mx[N],w[N],len[N];//前缀最大值,1到i递增序列长度,i到n的递增序列长度 8 int que[N],ed,top,fa[N],pp[N];//队列,栈底,栈顶,fa[i]下一个比i大的位置,pp[i]表示1~i递增序列的最后一个下标 9 int ls[M],rs[M],mi[M],rt[N],tot,sz;//左右儿子,位置, 10 void init() 11 { 12 tot=ed=top=0; 13 } 14 void update(int &o,int pre,int l,int r,int x,int p) 15 { 16 o=++tot;ls[o]=ls[pre];rs[o]=rs[pre]; 17 mi[o]=min(mi[pre],p); 18 if(l==r)return; 19 int m=(l+r)>>1; 20 if(x<=m) update(ls[o],ls[pre],l,m,x,p); 21 else update(rs[o],rs[pre],m+1,r,x,p); 22 } 23 int query(int rt,int l,int r,int p) 24 { 25 if(!rt||p>r)return n+1; 26 if(p<=l)return mi[rt]; 27 int m=(l+r)>>1; 28 if(p<=m)return min(query(ls[rt],l,m,p),query(rs[rt],m+1,r,p)); 29 return query(rs[rt],m+1,r,p); 30 } 31 int main(){ 32 int T; 33 scanf("%d",&T); 34 while(T--) 35 { 36 init(); 37 scanf("%d %d",&n,&m); 38 for(int i=1;i<=n;i++) 39 { 40 scanf("%d",&h[i]); 41 } 42 for(int i=1;i<=n;i++) 43 { 44 if(h[i]>mx[i-1]) 45 { 46 mx[i]=h[i]; w[i]=w[i-1]+1; pp[i]=i; 47 } 48 else 49 { 50 mx[i]=mx[i-1];w[i]=w[i-1]; pp[i]=pp[i-1]; 51 } 52 } 53 for(int i=n;i>=1;i--) 54 { 55 while(top>ed&&h[que[top]]<=h[i])top--; 56 que[++top]=i; 57 len[i]=top-ed; 58 if(top-ed>1)fa[i]=que[top-1]; 59 else fa[i]=n+1; 60 } 61 mi[0]=n+1;rt[n+1]=0;len[n+1]=0; 62 for(int i=n;i>=1;i--) 63 { 64 update(rt[i],rt[i+1],1,1e9,h[i],i); 65 } 66 while(m--) 67 { 68 int p,x; 69 scanf("%d %d",&p,&x); 70 if(p==1) 71 { 72 printf("%d ",1+len[query(rt[p+1],1,1e9,x+1)]); 73 } 74 else 75 { 76 int pre=pp[p-1]; 77 if(fa[pre]==p) 78 { 79 if(x>h[pre])printf("%d ",w[p]+len[query(rt[p+1],1,1e9,x+1)]); 80 else printf("%d ",w[pre]+len[query(rt[p+1],1,1e9,h[pre]+1)]); 81 } 82 else 83 { 84 if(x>h[pre])printf("%d ",1+w[p]+len[query(rt[p+1],1,1e9,x+1)]); 85 else printf("%d ",w[n]); 86 } 87 } 88 } 89 } 90 return 0; 91 }