日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

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

生活随笔

當(dāng)前位置: 首頁(yè) >

HDU - 5008 Boring String Problem(后缀树求本质不同第k大子串)

發(fā)布時(shí)間:2024/4/11 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU - 5008 Boring String Problem(后缀树求本质不同第k大子串) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目鏈接:點(diǎn)擊查看

題目大意:給出一個(gè)長(zhǎng)度為 nnn 的字符串,再給出 mmm 次詢問(wèn),每次詢問(wèn)需要輸出本質(zhì)不同第 kkk 小的子串的起止位置。如果有多個(gè)答案,輸出起點(diǎn)最小的那個(gè)。強(qiáng)制在線。

題目分析:后綴樹(shù)的模板題,在后綴樹(shù)上按照字典序前序遍歷維護(hù)一下前綴和(子串個(gè)數(shù)),然后對(duì)于每次詢問(wèn)就可以二分查找答案在哪個(gè)節(jié)點(diǎn)了。

具體難點(diǎn)有兩條:

  • 如何在后綴樹(shù)上按照字典序遍歷
  • 如何維護(hù)每個(gè)子串首次出現(xiàn)的位置
  • 對(duì)應(yīng)的解決方案如下:

  • 根據(jù) parent 樹(shù)邊的性質(zhì)將子節(jié)點(diǎn)排序
  • 維護(hù) endpos 的極值
  • 那么如何求后綴樹(shù)呢?其實(shí)只需要將字符串反轉(zhuǎn)一下,然后扔到后綴自動(dòng)機(jī)里,此時(shí)求出的 parentparentparent 樹(shù)就是后綴樹(shù)了。

    原理也十分簡(jiǎn)單,考慮 parentparentparent 樹(shù)的葉子節(jié)點(diǎn)到根節(jié)點(diǎn)的一條路徑,表示的是一個(gè)前綴的所有后綴,反轉(zhuǎn)一下自然就變成了一個(gè)后綴的所有前綴,也就是后綴樹(shù)了。

    因?yàn)楸绢}需要記錄相應(yīng)子串的首次出現(xiàn)位置,所以可以維護(hù)一下反串中每個(gè)節(jié)點(diǎn)的 endposendposendpos 的最大值用于答案輸出。

    剩下的就是億點(diǎn)點(diǎn)坐標(biāo)轉(zhuǎn)換的細(xì)節(jié)了,大家可以用樣例以及:

    abcd
    1
    0
    ans=1 1

    這組樣例自己調(diào)一下,都能調(diào)過(guò)去的話應(yīng)該就沒(méi)有問(wèn)題了。

    代碼:

    // #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<list> #include<unordered_map> #define lowbit(x) (x&-x) using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=1e5+100; char s[N]; vector<int>node[N<<1]; int tot,last,endpos[N<<1]; LL sum[N<<1]; int rk[N<<1],dfn; struct Node {int ch[26];int fa,len; }st[N<<1]; inline int newnode() {tot++;for(int i=0;i<26;i++)st[tot].ch[i]=0;st[tot].fa=st[tot].len=0;endpos[tot]=0;node[tot].clear();return tot; } void add(int x) {int p=last,np=last=newnode();st[np].len=st[p].len+1;while(p&&!st[p].ch[x])st[p].ch[x]=np,p=st[p].fa;if(!p)st[np].fa=1;else{int q=st[p].ch[x];if(st[p].len+1==st[q].len)st[np].fa=q;else{int nq=newnode();st[nq]=st[q]; st[nq].len=st[p].len+1;st[q].fa=st[np].fa=nq;while(p&&st[p].ch[x]==q)st[p].ch[x]=nq,p=st[p].fa;//向上把所有q都替換成nq}} } void dfs_pos(int u) {for(auto v:node[u]) {dfs_pos(v);endpos[u]=max(endpos[u],endpos[v]);} } void dfs(int u,int fa) {if(u!=1) {dfn++;sum[dfn]=sum[dfn-1]+(st[u].len-st[fa].len);rk[dfn]=u;}vector<pair<char,int>>son;for(auto v:node[u]) {son.push_back({s[endpos[v]-st[u].len],v});}sort(son.begin(),son.end());for(auto it:son) {dfs(it.second,u);} } void build() {for(int i=1;i<=tot;i++) {node[st[i].fa].push_back(i);}dfs_pos(1);dfs(1,-1); } void init() {last=1;dfn=tot=0;newnode(); } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);while(scanf("%s",s+1)!=EOF) {init();int n=strlen(s+1);reverse(s+1,s+1+n);for(int i=1;i<=n;i++) {add(s[i]-'a');endpos[last]=i;}build();int m;scanf("%d",&m);LL l=0,r=0;while(m--) {LL k;scanf("%lld",&k);k=(k^l^r)+1;if(k<=sum[dfn]) {int t=lower_bound(sum+1,sum+1+dfn,k)-sum;int u=rk[t];int len=st[u].len-(sum[t]-k);l=n-endpos[u]+1;r=l+len-1;} else {l=r=0;}printf("%lld %lld\n",l,r);}}return 0; }

    總結(jié)

    以上是生活随笔為你收集整理的HDU - 5008 Boring String Problem(后缀树求本质不同第k大子串)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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