[bzoj3879]SvT_后缀数组_RMQ_单调栈
生活随笔
收集整理的這篇文章主要介紹了
[bzoj3879]SvT_后缀数组_RMQ_单调栈
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
SvT bzoj-3879
題目大意:給定一個(gè)字符串。每次詢(xún)問(wèn)給定$t$個(gè)位置,求兩兩位置開(kāi)頭的后綴的$LCP$之和。
注釋:$1\le length\le 5\cdot 10^5$,$\sum t\le 3\cdot 10^6$。
想法:
不難想到構(gòu)建后綴數(shù)組。
進(jìn)而我們的問(wèn)題就轉(zhuǎn)化成了給定序列上一些位置求這些位置兩兩之間區(qū)間最小值的和。
對(duì)$ht$數(shù)組建立$ST$表。
接下來(lái)的過(guò)程可以用單調(diào)棧維護(hù)。
Code:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define N 500010 using namespace std; typedef long long ll; int n,m,wa[N],wb[N],wv[N],sa[N],height[N],rank[N],r[N],Ws[N]; char ch[N]; int f[21][N],L[N],vis[N],s[N],g[N]; int v[3000050],Q[3000050]; ll dp[N]; inline char nc() {static char buf[100000],*p1,*p2;return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int rd() {int x=0; char c=nc();while(c<'0'||c>'9') c=nc();while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=nc();return x; } inline int rc() {char c=nc();while(c<'a'||c>'z') c=nc();return (int)c; }void build_sa() {m=27;int i,j,p,*x=wa,*y=wb,*t;for(i=0;i<m;i++) Ws[i]=0;for(i=0;i<n;i++) Ws[x[i]=r[i]]++;for(i=1;i<m;i++) Ws[i]+=Ws[i-1];for(i=n-1;i>=0;i--) sa[--Ws[x[i]]]=i;for(p=j=1;p<n;j<<=1,m=p){for(p=0,i=n-j;i<n;i++) y[p++]=i;for(i=0;i<n;i++) if(sa[i]-j>=0) y[p++]=sa[i]-j;for(i=0;i<n;i++) wv[i]=x[y[i]];for(i=0;i<m;i++) Ws[i]=0;for(i=0;i<n;i++) Ws[wv[i]]++;for(i=1;i<m;i++) Ws[i]+=Ws[i-1];for(i=n-1;i>=0;i--) sa[--Ws[wv[i]]]=y[i];for(t=x,x=y,y=t,i=p=1,x[sa[0]]=0;i<n;i++){if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]) x[sa[i]]=p-1;else x[sa[i]]=p++;}}for(i=1;i<n;i++) rank[sa[i]]=i;for(i=p=0;i<n-1;height[rank[i++]]=p)for(p?p--:0,j=sa[rank[i]-1];r[i+p]==r[j+p];p++); } int get_min(int l,int r) {int len=L[r-l+1];return min(f[len][l],f[len][r-(1<<len)+1]); } void ST() {int i,j;for(i=2;i<=n;i++) L[i]=L[i>>1]+1;for(i=1;i<=n;i++) f[0][i]=height[i];for(i=1;(1<<i)<=n;i++){for(j=1;j+(1<<i)-1<=n;j++) f[i][j]=min(f[i-1][j],f[i-1][j+(1<<(i-1))]);} } bool cmp(int x,int y) {return rank[x]<rank[y]; } int main() {int T;n=rd(); T=rd();int i;for(i=0;i<n;i++) r[i]=rc()-'a'+1;r[n++]=0;int tot=0;build_sa(); n--; ST();while(T--){tot++;int t=0;v[0]=rd();int j;for(j=1;j<=v[0];j++){v[j]=rd();v[j]--;if(vis[v[j]]==tot) {j--; v[0]--;}vis[v[j]]=tot;}sort(v+1,v+v[0]+1,cmp);for(j=1;j<v[0];j++){g[j]=get_min(rank[v[j]]+1,rank[v[j+1]]);}t=1; Q[1]=0;long long ans=0;for(j=1;j<v[0];j++){while(t&&g[Q[t]]>g[j]) t--;dp[j]=dp[Q[t]]+1ll*(j-Q[t])*g[j];ans+=dp[j];Q[++t]=j;}printf("%lld\n",ans);}return 0; }小結(jié):后綴數(shù)組真好玩。
轉(zhuǎn)載于:https://www.cnblogs.com/ShuraK/p/10132284.html
總結(jié)
以上是生活随笔為你收集整理的[bzoj3879]SvT_后缀数组_RMQ_单调栈的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CentOS7.5实践快速部署LAMP+
- 下一篇: 垂直margin合并问题