SPOJ - NSUBSTR Substrings

这里写代码片You are given a string S which consists of 250000 lowercase latin letters at most. We define F(x) as the maximal number of times that some string with length x appears in S. For example for string ‘ababa’ F(3) will be 2 because there is a string ‘aba’ that occurs twice. Your task is to output F(i) for every i so that 1<=i<=|S|.

Input
String S consists of at most 250000 lowercase latin letters.

Output
Output |S| lines. On the i-th line output F(i).

Example
Input:
ababa

Output:
3
2
2
1
1
题意:给出一个字符串,问每个长度最多有多少个相同的子串。
做法:对于每一个字母st[i] = x,以它结尾的子串可以用s0s1,,si所在的节点和这个节点的所有祖先表示,每个祖先可以表示以它结尾的mr到ml这一段,那么如果给每个这样的节点赋值为1,那么每一个节点代表的字符串出现的次数就是他所有儿子的1的和,现在插入的时候把这样的节点赋值为1,在插入结束的是用拓扑序统计每个节点出现的次数,因为每个节点代表的是一段区间,那么可以用线段树区间更新维护这个东西,但是我在用线段树时,每次查询i到i的值,结果T了,然后我把查询改成了递归就a了,,,
还有一个更好的做法,就是对于每个节点,只更新它的mx值,然后对于d[i] = max(d[i],d[i+1])就可以得到每个长度最大的值了,

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int N = 3e5+7;
char st[N];
int sum[N<<2],lz[N<<2];


void pushdown(int rt){
    if(lz[rt]){
        sum[rt<<1] = max(sum[rt<<1],lz[rt]);
        sum[rt<<1|1] = max(sum[rt<<1|1],lz[rt]);
        lz[rt<<1] = max(lz[rt<<1],lz[rt]);
        lz[rt<<1|1] = max(lz[rt<<1|1],lz[rt]);
        lz[rt] = 0;
    }
}

void update(int L,int R,int c,int l,int r,int rt){
    if(L <= l && R >= r){
        sum[rt] = max(sum[rt],c);
        lz[rt] = max(lz[rt],c);
        return ;
    }
    pushdown(rt);
    int mid = l+r>>1;
    if(mid >= L) update(L,R,c,l,mid,rt<<1);
    if(mid < R) update(L,R,c,mid+1,r,rt<<1|1);
    sum[rt] = max(sum[rt<<1],sum[rt<<1|1]);
}

int query(int L,int R,int l,int r,int rt){
    if(L <= l && R>= r) return sum[rt];
    pushdown(rt);
    int mid = l+r>>1;
    int ans = 0;
    if(mid >= L) ans = query(L,R,l,mid,rt<<1);
    if(mid < R) ans = max(ans,query(L,R,mid+1,r,rt<<1|1));
    return ans;
}

struct SAM{
    int pre[N*2],nex[N*2][26],mx[N*2],cnt[N*2],top,last;
    int son[N*2];
    void init(){
        top = 2;
        last = 1;
        memset(nex[1],0,sizeof(nex[1]));
    }
    int newnode(int x){
        memset(nex[top],0,sizeof(nex[top]));
        mx[top] = x;
        return top++;
    }
    void add(int x){
        int p = last;
        int np = newnode(mx[p]+1);
        while(p && nex[p][x] == 0) nex[p][x] = np,p = pre[p];
        if(p == 0){
            pre[np] = 1;
        }
        else{
            int q = nex[p][x];
            if(mx[q] == mx[p]+1){
                pre[np] = q;
            }
            else{
                int nq = newnode(mx[p]+1);
                for(int i = 0;i < 26;i ++) nex[nq][i] = nex[q][i];
                pre[nq] = pre[q];
                pre[np] = pre[q] = nq;
                son[nq]++;
                while(p && nex[p][x] == q) {
                    nex[p][x] = nq;
                    p = pre[p];
                }
            }
        }
        //cout << x << ' '<< pre[np] << ' '<< np << endl;
        son[pre[np]]++;
        last = np;
        cnt[np] = 1;
    }
    void solve(){
        queue<int> que;
        for(int i = 2;i < top;i ++)if(son[i] == 0) que.push(i);
        while(!que.empty()){
            int nx = que.front();
            que.pop();
            if(pre[nx] == 0)continue;
            son[pre[nx]]--;
            //cout << nx <<  ' '<< pre[nx] <<' '<< cnt[nx] <<endl;
            cnt[pre[nx]] += cnt[nx];
            if(son[pre[nx]] == 0) que.push(pre[nx]);
        }
    }
}sa;

int main(){
    scanf("%s",st);
    int len =strlen(st);
    sa.init();
    for(int i = 0;i < len;i ++) {sa.add(st[i]-'a');}

    sa.solve();
    for(int i = 2;i < sa.top;i ++){
        int nl = sa.mx[sa.pre[i]]+1;
        int nr = sa.mx[i];
        if(nl < 1 || nr > len || nl > nr) continue;
        update(nl,nr,sa.cnt[i],1,len,1);
    }
    for(int i = 1;i <= len;i ++){
        printf("%d\n",query(i,i,1,len,1));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zstu_zy/article/details/81260038
今日推荐