Wi Know——思维(线段树辅助)

Posted judp

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Wi Know——思维(线段树辅助)相关的知识,希望对你有一定的参考价值。

传送:

https://cn.vjudge.net/problem/Kattis-wiknow

题意:

在字符串中找形如ABAB的子序列,要求AB字典序最小。

思路:

这道题最重要的性质:如果存在形如ABAB的子序列,那么一定可以找到一个A1B1A2B2,满足A1A2之间没有其它A,B1B2之间没有其它B。

先预处理每个字符右边一个的位置。扫描一遍字符串,把每个字符右边一个加入线段树,同时枚举B1,在B1,B2之间区间最小查询,这个最小值一定在B1左边出现过,因为更新线段树时是加入每个字符右边的。

code:

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef pair<int,int> P;
 4 const int N=400000+10;
 5 const int INF=0x3f3f3f3f;
 6 int dat[4*N];
 7 int a[N],nex[N],r[N],n;
 8 void update(int pos,int k,int l,int r)
 9 
10     if(r-l==1)dat[k]=a[pos];return;
11     int m=(l+r)>>1;
12     if(pos<m)update(pos,k<<1,l,m);
13     else update(pos,(k<<1)|1,m,r);
14     dat[k]=min(dat[k<<1],dat[(k<<1)|1]);
15 
16 int query(int a,int b,int k,int l,int r)
17 
18     if(l==r)return INF;
19     if(a<=l&&b>=r)return dat[k];
20     int m=(l+r)>>1,mi=INF;
21     if(a<m)mi=min(mi,query(a,b,k<<1,l,m));
22     if(b>m)mi=min(mi,query(a,b,(k<<1)|1,m,r));
23     return mi;
24 
25 int main()
26 
27     memset(dat,0x3f,sizeof(dat));
28     scanf("%d",&n);
29     for(int i=1;i<=n;++i)
30         scanf("%d",a+i);
31     for(int i=n;i>=1;--i)//处理每个字符右边一个的位置
32     
33         nex[i]=r[a[i]];
34         r[a[i]]=i;
35     
36     P ans(INF,INF);
37     for(int i=1;i<=n;++i)
38     
39         if(!nex[i])continue;
40         int v=query(i+1,nex[i],1,1,n+1);//在当前位置与下一个位置之间查询最小值
41         ans=min(ans,make_pair(v,a[i]));
42         update(nex[i],1,1,n+1);//把当前字符下一个更新进线段树
43     
44     if(ans.first==INF||ans.second==INF)
45         puts("-1");
46     else printf("%d %d\n",ans.first,ans.second);
47     return 0;
48 
View Code

 

 

以上是关于Wi Know——思维(线段树辅助)的主要内容,如果未能解决你的问题,请参考以下文章

19徐州网络赛E 线段树加离散化

P2787 语文1(chin1)- 理理思维(线段树)

Codeforces 755D(思维+线段树)

HDU - 2795 Billboard (线段树)

FZU 2297 Number theory线段树/单点更新/思维

Buy Tickets POJ - 2828 思维+线段树