51Nod 1600 Simple KMP

来源:互联网 发布:反骨是什么网络用语 编辑:程序博客网 时间:2024/05/20 05:30

SAM+LCT/树剖线段树

一个点的深度就是有多少个以这个点结尾的后缀等于前缀。fail树性质不太够,不好下手,直接考虑答案的贡献。对于两个相等的区间[l,r]&[x,y]其中l

#include<cstdio>#include<cstring>#include<iostream>#define N 100005#define MOD 1000000007#define A 28#define pr(_i) cout<<#_i<<" = "<<_i<<endlusing namespace std;namespace runzhe2000{    typedef long long ll;    int n, ecnt, last[N<<1], q[N], top[N<<1], siz[N<<1], son[N<<1], dep[N<<1], fa[N<<1], beg[N<<1], rebeg[N<<1], timer;    char s[N];    struct edge{int next, to;}e[N<<1];    void addedge(int a, int b)    {        e[++ecnt] = (edge){last[a], b};        last[a] = ecnt;    }    struct SAM    {        SAM *fail, *next[A];        int len;    }mem[N<<1], *tot, *null, *lastp, *root;    SAM *newSAM(){SAM *p = ++tot; *p = *null; return p;}     void init_SAM()    {        null = tot = mem;        null->fail = null;        for(int i = 0; i < A; i++) null->next[i] = null;        lastp = root = newSAM();    }    void extend(int v)    {         SAM *p = lastp, *np = newSAM(); lastp = np; np->len = p->len + 1;        for(; p->next[v] == null && p != null; p = p->fail) p->next[v] = np;        if(p == null) np->fail = root;        else        {            SAM *q = p->next[v];            if(p->len + 1 == q->len)np->fail = q;            else            {                SAM *nq = newSAM(); nq->len = p->len + 1;                memcpy(nq->next, q->next, sizeof(q->next));                nq->fail = q->fail; q->fail = np->fail = nq;                for(; p->next[v] == q && p != null; p = p->fail) p->next[v] = nq;            }        }    }       struct seg    {        int sum, tag1, tag2, lazy;    }t[N*8];    void pushup(int x)    {        t[x].sum = (t[x<<1].sum + t[x<<1|1].sum) % MOD;        t[x].tag1 = (t[x<<1].tag1 + t[x<<1|1].tag1) % MOD;        t[x].tag2 = (t[x<<1].tag2 + t[x<<1|1].tag2) % MOD;    }    void build(int x, int l, int r)    {        if(l == r){t[x].tag1 = -(t[x].tag2 = mem[rebeg[l]].len - mem[rebeg[l]].fail->len); return;}        int mid = (l+r)>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r);         pushup(x);    }    void add(int x, int c)    {        (t[x].sum += ((ll)t[x].tag2*c%MOD*c%MOD + (ll)t[x].tag1*c%MOD)*(MOD-MOD/2)%MOD) %= MOD;        (t[x].tag1 += (ll)t[x].tag2*c%MOD*2%MOD) %= MOD; (t[x].lazy += c) %= MOD;    }    void pushdown(int x)    {        if(!t[x].lazy) return;        add(x<<1,t[x].lazy); add(x<<1|1,t[x].lazy);        t[x].lazy = 0;    }    void modi(int x, int l, int r, int ql, int qr, int c)    {        if(ql <= l && r <= qr) return (void)add(x,c); int mid = (l+r)>>1; pushdown(x);        if(ql <= mid) modi(x<<1,l,mid,ql,qr,c); if(mid < qr) modi(x<<1|1,mid+1,r,ql,qr,c);        pushup(x);          }    void dfs1(int x)    {        dep[x] = dep[fa[x]] + 1; siz[x] = 1;        for(int i = last[x]; i; i = e[i].next)        {            int y = e[i].to; if(y == fa[x]) continue;            fa[y] = x; dfs1(y); siz[x] += siz[y];            siz[y] > siz[son[x]] ? son[x] = y : 0;        }    }    void dfs2(int x)    {        rebeg[beg[x] = ++timer] = x;         top[x] = son[fa[x]] == x ? top[fa[x]] : x;        if(son[x]) dfs2(son[x]);        for(int i = last[x]; i; i = e[i].next)        {            int y = e[i].to; if(y == fa[x] || y == son[x]) continue;            dfs2(y);        }    }    void main()    {        scanf("%d%s",&n,s+1);        init_SAM();        for(int i = 1; i <= n; i++)        {            extend(s[i] - 'a');            q[i] = lastp - mem;        }        for(SAM *i = tot; i != mem; i--) addedge(i->fail - mem, i - mem);        dfs1(1); dfs2(1); int totmem = tot-mem; build(1,1,totmem);        int ans = 0;        for(int i = 1; i <= n; i++)        {            int x = q[i];            for(; x; x = fa[top[x]]) modi(1,1,totmem,beg[top[x]],beg[x], 1);            (ans += t[1].sum) %= MOD;            printf("%d\n",(ans+MOD)%MOD);        }    }}int main(){    runzhe2000::main();}
0 0
原创粉丝点击