日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

[bzoj3879]SvT_后缀数组_RMQ_单调栈

發(fā)布時(shí)間:2025/3/15 编程问答 11 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [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)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。