bzoj 2882 工艺

 

思路:  

  这是字符串最大最小表示法的题,今天用后缀自动机做一下。

sam:

#include <bits/stdc++.h>

using namespace std;

struct SAM
{
    static const int MAXN = 300001<<1;//大小为字符串长度两倍

    map<int,int>ch[MAXN];
    int tot, last, fa[MAXN], len[MAXN];
    int sum[MAXN], tp[MAXN], cnt[MAXN]; //sum,tp用于拓扑排序,tp为排序后的数组

    void init( void)
    {
        last = tot = 1;
    }

    void add( int x)
    {
        int p = last, np = last = ++tot;
        len[np] = len[p] + 1, cnt[last] = 1;
        while( p && !ch[p].count(x)) ch[p][x] = np, p = fa[p];
        if( p == 0)
            fa[np] = 1;
        else
        {
            int q = ch[p][x];
            if( len[q] == len[p] + 1)
                fa[np] = q;
            else
            {
                int nq = ++tot;
                ch[nq]=ch[q];
                len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
                while( p && ch[p].count(x) && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
            }
        }
    }

    void toposort( void)
    {
        for(int i = 1; i <= len[last]; i++)   sum[i] = 0;
        for(int i = 1; i <= tot; i++)   sum[len[i]]++;
        for(int i = 1; i <= len[last]; i++)   sum[i] += sum[i-1];
        for(int i = 1; i <= tot; i++)   tp[sum[len[i]]--] = i;
        for(int i = tot; i; i--)   cnt[fa[tp[i]]] += cnt[tp[i]];
    }

    void solve( int n)
    {
        for(int i=1,p=1;i<=n;i++)
            printf("%d ",ch[p].begin()->first),p=ch[p].begin()->second;
    }
} sam;

int a[300003];
int main(void)
{
    int n;cin>>n;
    sam.init();
    for(int i=1;i<=n;i++)   scanf("%d",a+i),sam.add(a[i]);
    for(int i=1;i<=n;i++)   sam.add(a[i]);
    sam.solve(n);
    return 0;
}

 

posted @ 2017-09-14 15:49  weeping  阅读(167)  评论(0编辑  收藏  举报