luogu3426 [POI2005]SZA-Template 后缀树

链接

bzoj不能auto
https://www.luogu.org/problemnew/show/P3426

思路

这个要求的串一定是S的前缀和S的后缀。
转化一下
建立出来fail树(fail[i]->i的树)
答案就在0和n之间的链条上,且答案在分界点上(上面全不可以,下面全可以)
这是样例的fail树

好了,我们从0到n挨着判断一下,n^2
其实满足条件就等价于我们选的这个前缀这个答案可以全部覆盖S串
就是说相邻的两个含有T的前缀串串的差<=|T|(这些串串一定在判断字符的子树内)
而且每次向下走的时候都要删除掉不是他子树内的点(因为他们不含有判定字符的前缀)
我们可以在删除的时候用链表维护子树内相邻的串的最大值
而且每个前缀只会被删一次,复杂度O(n)

错误

有点复杂度错误
bzoj不能auto、、、、

代码

#include <bits/stdc++.h>
using namespace std;
const int N=5e5+7;
int n,fail[N],head=1,vis[N],ma=1;
char s[N];
vector<int> G[N];
struct node {int las,u,nxt;}e[N];
void del(int u) {
    if(vis[u]) return;
    e[e[u].las].nxt=e[u].nxt;
    e[e[u].nxt].las=e[u].las;
    if(e[e[u].nxt].u&&e[e[u].las].u)
        ma=max(ma,e[e[u].nxt].u-e[e[u].las].u);
//  for(auto v:G[u]) del(v);
//  for(int v=0;v<G[u].size();++v) del(v);
    for(vector<int>::iterator v=G[u].begin();v!=G[u].end();++v) del(*v);
}
void dfs(int u) {
    vis[u]=0;
    if(u>=ma) {printf("%d\n",u);exit(0);}
    del(u);
//  for(auto v:G[u])if(vis[v])dfs(v);
//  for(int v=0;v<G[u].size();++v) if(vis[v])dfs(v);
    for(vector<int>::iterator v=G[u].begin();v!=G[u].end();++v) if(vis[*v])dfs(*v);
}
int main() {
//    freopen("a.in","r",stdin);
//    freopen("a.out","w",stdout);
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=2,p=0;i<=n;++i) {
        while(p>0&&s[i]!=s[p+1]) p=fail[p];
        if(s[i]==s[p+1]) p++;
        fail[i]=p;
    }
    for(int i=1;i<=n;++i) G[fail[i]].push_back(i),cout<<fail[i]<<" "<<i<<"\n";
    for(int p=n;p;p=fail[p]) vis[p]=1;
    for(int i=1;i<=n;++i) e[i].las=i-1,e[i].nxt=i+1,e[i].u=i;e[n].nxt=0;
    dfs(0);
    return 0;
}
全部评论

相关推荐

废铁汽车人:秋招真是牛鬼蛇神齐聚一堂
点赞 评论 收藏
分享
SinyWu:七院电话面的时候问我有没有女朋友,一听异地说你赶紧分。我:???
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务