Wi Know (思维+线段树)

Wi Know 

题意:在字符串中找ABAB形的子序列,输出字典序最小的AB

题解:枚举每个位置作为B1,在该位置与这个字符的下一个位置B2之间查找最小的A2,而在B1之前,所有字符都可以作为A1,已经把它们的下一个A2放到了线段树里。

AC_Code:

 1 #include 
 2 using namespace std;
 3 typedef long long ll;
 4 #define endl '\n'
 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\n",ans.first, ans.second);
47     else printf("-1\n");
48     return 0;
49 }

 

你可能感兴趣的:(Wi Know (思维+线段树))