题意:在字符串中找ABAB形的子序列,输出字典序最小的AB
题解:枚举每个位置作为B1,在该位置与这个字符的下一个位置B2之间查找最小的A2,而在B1之前,所有字符都可以作为A1,已经把它们的下一个A2放到了线段树里。
AC_Code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define endl ' ' 5 const int mod=6000; 6 const int maxn=5e5+10; 7 const int inf=0x3f3f3f3f; 8 9 int a[maxn],nxt[maxn],pos[maxn],n; 10 int tree[maxn<<2],lz[maxn<<2]; 11 pair<int,int>ans=make_pair(inf,inf); 12 13 int query(int rt,int l,int r,int ql,int qr){ 14 if( ql<=l && r<=qr ) return tree[rt]; 15 int mid=(l+r)>>1; 16 int minn=inf; 17 if( ql<=mid ) minn=min(minn,query(rt<<1,l,mid,ql,qr)); 18 if( qr>mid ) minn=min(minn,query(rt<<1|1,mid+1,r,ql,qr)); 19 return minn; 20 } 21 22 void update(int rt,int l,int r,int pos){//线段树更新区间字典序最小的字符 23 if( l==r ) tree[rt]=a[pos]; 24 else{ 25 int mid=(l+r)>>1; 26 if( pos<=mid ) update(rt<<1,l,mid,pos); 27 else update(rt<<1|1,mid+1,r,pos); 28 tree[rt]=min(tree[rt<<1],tree[rt<<1|1]); 29 } 30 } 31 32 int main() 33 { 34 memset(tree,inf,sizeof(tree)); 35 scanf("%d",&n); 36 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 37 for(int i=n;i>=1;i--){ 38 nxt[i]=pos[a[i]]; //nxt数组存a[i]下一次出现的位置 39 pos[a[i]]=i; 40 } 41 for(int i=1;i<=n;i++){ 42 if( nxt[i]==0 ) continue; 43 ans=min(ans, make_pair(query(1,1,n,i+1,nxt[i]-1),a[i])); 44 update(1,1,n,nxt[i]); 45 } 46 if( ans.first!=inf && ans.second!=inf ) printf("%d %d ",ans.first, ans.second); 47 else printf("-1 "); 48 return 0; 49 }