其他分享
首页 > 其他分享> > 2021 ccpc桂林 J - Suffix Automaton(后缀自动机+线段树)

2021 ccpc桂林 J - Suffix Automaton(后缀自动机+线段树)

作者:互联网

题目地址
赛中到最后时间不够,写的时候脑袋混乱,后来因为不明错误样例都没调过...没拿金我背大锅。
赛后重新整理下思路,直接A了,哎....
思路:首先对子串字典序问题有个经典做法是反串建后缀自动机,然后建出parent树,其中在建树时边权是子节点比父节点刚好多出一个的字符,这样这个树的dfs序就刚好是子串的字典序了,然后题目中是在子串长度相等的基础上比较字典序,否则比较长度,那么对于树上的某一个节点,由于其代表的子串长度是连续的,所以可以利用差分的思想,将这个子串的信息存到差分数组的该子串的最短长度和最长长度+1上,代表这段区间的长度含这个子串。然后就先按从小到大离线询问,然后对于每个询问,算出这个询问代表的子串的长度k和在这个长度里排第几x,然后将差分数组的指针一步步移到当前长度,一边移动一边更新线段树(将相应的dfs序更新),然后查询线段树中第x个出现的下标即可。由于最后答案要求是最左边出现的子串的下标,也就是要求反串后最右下标,可以从parent树从叶子往上更新位置的最大值。

越想越气...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <time.h>
#include <map>
#include <algorithm>
#include <fstream>
//#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1000000 + 100;
const int INF = 0x7fffffff;
const int mod = 998244353;
const ll mod1 = 998244353;
const ll base = 137;
const double Pi = acos(-1.0);
const int G = 3;
struct state
{
    int len, link;
    //std::map<char, int> next;
    int nxt[26];
    int pos;
};
const int MAXLEN = 1000000 + 5;
state st[MAXLEN * 2];
int sz, last;
void sam_init()
{
    memset(st[0].nxt, 0, sizeof(st[0].nxt));
    sz = 0;
    st[0].len = 0;
    st[0].link = -1;
    sz++;
    last = 0;
}
int cur;
void sam_extend(char c, int id)
{
    cur = sz++;
    st[cur].pos = id;
    st[cur].len = st[last].len + 1;
    int p = last;
    while (p != -1 && !st[p].nxt[c - 'a'])
    {
        st[p].nxt[c - 'a'] = cur;
        p = st[p].link;
    }
    if (p == -1)
    {
        st[cur].link = 0;
    }
    else
    {
        int q = st[p].nxt[c - 'a'];
        if (st[p].len + 1 == st[q].len)
        {
            st[cur].link = q;
        }
        else
        {
            int clone = sz++;
            st[clone].len = st[p].len + 1;
            memcpy(st[clone].nxt, st[q].nxt, sizeof(st[clone].nxt));
          //  st[clone].pos = st[q].pos;
            //st[clone].next = st[q].next;
            st[clone].link = st[q].link;
            while (p != -1 && st[p].nxt[c - 'a'] == q)
            {
                st[p].nxt[c - 'a'] = clone;
                p = st[p].link;
            }
            st[q].link = st[cur].link = clone;
        }
    }
    last = cur;
    //siz[cur]=1;
}
int len[maxn];
int a[maxn*2];
int n;
void getSiz()
{
    for(int i=1;i<sz;i++)
    {
        len[st[i].len]++;
    }
    for(int i=n;i>=1;i--)
    {
        len[i]+=len[i+1];
    }
    for(int i=1;i<sz;i++)
    {
        a[len[st[i].len]--]=i;
    }
    for(int i=1;i<sz;i++)
    {
        int p=a[i];
        st[st[p].link].pos=max(st[st[p].link].pos,st[p].pos);
    }
}
char s[maxn];
struct node
{
    int id;
    ll x;
} qu[maxn];
bool cmp(node a, node b)
{
    return a.x < b.x;
}
struct NNode
{
    int to;
    int str;
    NNode(int tt = 0, int ss = 0)
    {
        to = tt;
        str = ss;
    }
};
vector<NNode> edge[maxn];
int in[maxn * 2];
int vis[maxn * 2];
int cnt;
void dfs(int x)
{
    in[x] = ++cnt;
    vis[cnt] = x;
    //cout<<222<<' '<<cnt<<' '<<x<<endl;
    for (int i = 0; i < (int)edge[x].size(); i++)
    {

        dfs(edge[x][i].to);
    }
}
struct pp
{
    int id;
    int f;
    pp(int ii, int ff)
    {
        id = ii;
        f = ff;
    }
};
vector<pp> v[maxn];
ll sum[maxn];
pair<int, int> ans[maxn];
struct Node
{
    int l, r, sum;
} tree[maxn * 8];
void build(int i, int l, int r)
{
    //cout<<i<<' '<<l<<' '<<r<<endl;
    tree[i].l = l;
    tree[i].r = r;
    if (l == r)
    {
        tree[i].sum = 0;
        return;
    }
    int mid = (l + r) >> 1;
    build(i * 2, l, mid);
    build(i * 2 + 1, mid + 1, r);
    tree[i].sum = 0;
}
void update(int i, int k, int x)
{
    if (tree[i].l == tree[i].r)
    {
        tree[i].sum += x;
        return;
    }
    if (tree[i * 2].r >= k)
        update(i * 2, k, x);
    if (tree[i * 2 + 1].l <= k)
        update(i * 2 + 1, k, x);
    tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum;
}
int query(int i, int k)
{
    //  cout<<i<<' '<<tree[i].l<<' '<<tree[i].r<<' '<<tree[i*2].sum<<' '<<k<<endl;
    if (tree[i].l == tree[i].r)
    {
        return tree[i].l;
    }
    int res;
    if (tree[i * 2].sum >= k)
        res = query(i * 2, k);
    else
        res = query(i * 2 + 1, k - tree[i * 2].sum);
    return res;
}
int dp[maxn];
bool cmp2(NNode a, NNode b)
{
    return a.str < b.str;
}
int main()
{
    scanf("%s", s + 1);
    int len = strlen(s + 1);
    n=len;
    for (int i = 1; i <= len / 2; i++)
    {
        swap(s[i], s[len - i + 1]);
    }
    sam_init();
    for (int i = 1; i <= len; i++)
        sam_extend(s[i], i);
    getSiz();
    //  printf("%s",s+1);
    for (int i = 1; i < sz; i++)
    {
        edge[st[i].link].push_back(NNode(i, s[st[i].pos - st[st[i].link].len] - 'a'));
        //  cout<<222<<' '<<st[i].pos<<' '<<st[st[i].link].len<<' '<<s[st[i].pos-st[st[i].link].len]-'a'<<endl;
    }
    for (int i = 0; i < sz; i++)
    {
        sort(edge[i].begin(), edge[i].end(), cmp2);
    }
    dfs(0);
    for (int i = 1; i < sz; i++)
    {
        v[st[st[i].link].len + 1].push_back(pp(i, 0));
        v[st[i].len + 1].push_back(pp(i, 1));
        dp[st[st[i].link].len + 1]++;
        dp[st[i].len + 1]--;
    }
    for (int i = 1; i <= len; i++)
    {
        sum[i] = sum[i - 1] + dp[i];
        //  cout<<111<<' '<<i<<' '<<sum[i]<<endl;
    }
    for (int i = 1; i <= len; i++)
    {
        sum[i] += sum[i - 1];
    }
    int q;
    scanf("%d", &q);
    for (int i = 1; i <= q; i++)
    {
        scanf("%lld", &qu[i].x);
        qu[i].id = i;
    }
    sort(qu + 1, qu + 1 + q, cmp);
    //cout<<len<<endl;
    build(1, 1, sz);
    int now = 1;
    for (int i = 1; i <= q; i++)
    {
        int le = lower_bound(sum + 1, sum + 1 + len, qu[i].x) - sum;
        int k = qu[i].x - sum[le - 1];
        //   cout<<le<<' '<<k<<endl;
        if (le > len)
        {
            ans[qu[i].id].first = -1;
            ans[qu[i].id].second = -1;
            continue;
        }
        while (now <= le)
        {
            for (auto j : v[now])
            {
                if (j.f == 0)
                {
                    update(1, in[j.id], 1);
                    // cout<<in[j.id]<<' '<<1<<endl;
                }
                else
                {
                    update(1, in[j.id], -1);
                }
            }
            now++;
        }
        int p = query(1, k);
        //  cout<<111<<' '<<k<<' '<<vis[p]<<endl;
        p=vis[p];
      //  while(st[st[p].link].len>=le) p=st[p].link;
        int l = st[p].pos - le + 1;
        int r = st[p].pos;
        ans[qu[i].id].first = len - r + 1;
        ans[qu[i].id].second = len - l + 1;
    }
    for (int i = 1; i <= q; i++)
    {
        printf("%d %d\n", ans[i].first, ans[i].second);
    }
    //  system("pause");
}

标签:Suffix,int,ccpc,len,st,link,2021,maxn,include
来源: https://www.cnblogs.com/lijiayi123/p/15557743.html