BZOJ5137[Usaco2017 Dec]Standing Out from the Herd

看了半天题 不知道怎么用SAM维护 于是借(chao)鉴(xi)的一发神犇的 只要判断这个子串之前被标记的记号(也就是他属于第几个串)和这次转移到的是否相同 如果不同就说明该子串属于多个串 直接标记-1 依次转移就好咧 最后统计就是ans[f[i]]+=sam[i].mxsam[par[i]].mx;f[i]就是他属于那个串

#include<bits/stdc++.h>
#define bug(x) cout<<(#x)<<" "<<(x)<<endl
#define ll long long
using namespace std;
const int N=2e5+5;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct Edge{
    int v,nxt;
}e[N*2];
struct data{
    int a[26],c;
}tr[N];
struct SAM{
    int par,mx,a[26];
}sam[N];
int tot,rt,rttot,cnt=1,n,len,r[N],head[N];
ll ans[N];
char s[N]; 
void ins(int u,int v){
    e[++tot].v=v,e[tot].nxt=head[u],head[u]=tot;
}
void update(int&c,int op){
    if(c==0) c=op;
    else c=(c==op)?c:-1;
}
int add(int p,int c,int op){
    int np=++rttot;
    sam[np].mx=sam[p].mx+1;
    update(r[np],op);
    for(;p&&!sam[p].a[c];p=sam[p].par) sam[p].a[c]=np;
    if(!p) sam[np].par=rt;
    else{
        int q=sam[p].a[c];
        if(sam[q].mx==sam[p].mx+1) sam[np].par=q;
        else{
            int nq=++rttot;
            sam[nq]=sam[q];
            sam[nq].mx=sam[p].mx+1;
            sam[q].par=sam[np].par=nq;
            for(;p&&sam[p].a[c]==q;p=sam[p].par) sam[p].a[c]=nq;
        }
    }
    return np;
}
void build(int op){
    int len=strlen(s+1),x=1;
    for(int i=1;i<=len;i++){
        update(tr[x].c,op);
        int c=s[i]-'a';
        if(!tr[x].a[c]) tr[x].a[c]=++cnt;
        x=tr[x].a[c];
    }
    update(tr[x].c,op);
}
void built(int x,int c,int p){
    int np;
    if(x==1) np=1;
    else np=add(p,c,tr[x].c);
    //bug(np);
    for(int i=0;i<26;i++) if(tr[x].a[i]) built(tr[x].a[i],i,np);
}
void dfs(int x){
    for(int i=head[x];i;i=e[i].nxt){
        int j=e[i].v;
        dfs(j);
        update(r[x],r[j]);
    }
    if(x!=1&&r[x]!=-1) ans[r[x]]+=sam[x].mx-sam[sam[x].par].mx; 
}
int main(){
#ifdef Devil_Gary
    freopen("in.txt","r",stdin);
#endif
    rttot=rt=1;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%s",s+1),
        build(i); 
    }
    built(1,0,0);
    for(int i=2;i<=rttot;i++) ins(sam[i].par,i);
    dfs(1);
    for(int i=1;i<=n;i++) printf("%lld\n",ans[i]);
    return 0;
}

posted @ 2018-01-12 18:19  Devil_Gary  阅读(100)  评论(0编辑  收藏  举报