彻彻底底坑了队友= =
A. Equivalent Prefixes
【考场上的想法】
从前往后扫,对于当前的一位置$i$,判断加入后是否equivalent,相当于判断$j=max\{j\text{|}a[j]<a[i],j<i\}$、$k=max\{k\text{|}b[k]<b[i],k<i\}$是否相等
这可以用二分+线段树懒标记解决:
每次区间赋值,是给$a[i],b[i]$对应的线段树的区间$[j+1,i]$分别赋$i$(若赋值,则默认了$j=k$),表示这段区间中最小的数的下标为$i$
然后对于新的$i$,可以二分找出$j$、$k$
总复杂度$O(n(logn)^2)$
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=100005; int n; int a[N],b[N]; struct SegTree { int sz; int t[N<<2],tag[N<<2]; void Init(int x) { sz=x; for(int i=1;i<(sz<<1);i++) t[i]=tag[i]=0; } inline void Push(int k) { if(!tag[k]) return; t[k]=tag[k]; tag[k]=0; if(k>=sz) return; tag[k<<1]=tag[k<<1|1]=t[k]; } inline void Add(int k,int l,int r,int a,int b,int x) { Push(k); if(a>r || b<l) return; if(a>=l && b<=r) { tag[k]=x; Push(k); return; } int mid=(a+b)>>1; Add(k<<1,l,r,a,mid,x); Add(k<<1|1,l,r,mid+1,b,x); } inline int Query(int k,int p,int a,int b) { Push(k); if(a==b) return t[k]; int mid=(a+b)>>1; if(p<=mid) return Query(k<<1,p,a,mid); else return Query(k<<1|1,p,mid+1,b); } }ta,tb; int main() { while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&b[i]); int sz=1; while(sz<n) sz<<=1; ta.Init(sz),tb.Init(sz); int ans=1; ta.Add(1,1,1,1,sz,1); tb.Add(1,1,1,1,sz,1); for(int i=2;i<=n;i++) { int pa,pb; int left=1,right=i-1,mid; while(left<right) { mid=(left+right)>>1; if(a[ta.Query(1,mid,1,sz)]<a[i]) left=mid+1; else right=mid; } if(a[left]>a[i]) left--; pa=left; left=1,right=i-1; while(left<right) { mid=(left+right)>>1; if(b[tb.Query(1,mid,1,sz)]<b[i]) left=mid+1; else right=mid; } if(b[left]>b[i]) left--; pb=left; if(pa!=pb) break; ans=i; ta.Add(1,pa+1,i,1,sz,i); tb.Add(1,pb+1,i,1,sz,i); } printf("%d\n",ans); } return 0; }
【正常做法】