2016集训测试赛(十九)Problem C: 无聊的字符串

Description

Solution

傻X题
我的方法是建立后缀后缀树, 然后在DFS序列上直接二分即可.
关键在于如何得到后缀树上每个字符对应的字节点: 我们要在后缀自动机上记录每个点在后缀树上对应的字母. 考虑如何实现, 我们在后缀自动机上的每个状态上, 记录其所对应的在字符串中的位置, 减去其父亲节点的长度即可得到每个节点对应的后缀树上的字符.

#include <cstdio>
#include <cstring>
#include <algorithm>
 
using namespace std;
const int LEN = (int)2e5;
struct suffixAutomaton
{
   int tp, rt, L, R;
   struct node
   {
       int suc[26], pre;
       int endPosition, len, c;
       int vst;
       int successorOnSuffixTree[26];
       inline node() {memset(suc, -1, sizeof(suc)); pre = -1; vst = 0; memset(successorOnSuffixTree, -1, sizeof(successorOnSuffixTree));}
   }nd[LEN << 1];
   void DFS(int u)
   {
       nd[u].vst = 1; if(u != rt) nd[nd[u].pre].successorOnSuffixTree[nd[u].c] = u;
       for(int i = 0; i < 26; ++ i) if(~ nd[u].suc[i] && ! nd[nd[u].suc[i]].vst) DFS(nd[u].suc[i]);
   }
   int clk;
   int idx[LEN << 1], sz[LEN << 1];
   long long sum[LEN << 1];
   inline void getId(int u)
   {
       int cur = clk ++;
       idx[cur] = u; sz[cur] = u == rt ? 0 : nd[u].len - nd[nd[u].pre].len;
       for(int i = 0; i < 26; ++ i) if(~ nd[u].successorOnSuffixTree[i])
       {
           int v = nd[u].successorOnSuffixTree[i];
           getId(v);
           if(nd[u].endPosition == -1 || nd[u].endPosition > nd[v].endPosition) nd[u].endPosition = nd[v].endPosition;
       }
   }
   inline void build(char *str, int len)
   {
       L = R = 0;
       rt = 0; nd[rt].len = 0; tp = 1;
       int lst = rt;
       for(int i = len - 1; ~ i; -- i)
       {
           char c = str[i] - 'a';
           int u = tp ++; nd[u].len = nd[lst].len + 1; nd[u].endPosition = i;
           for(; ~ lst && nd[lst].suc[c] == -1; lst = nd[lst].pre) nd[lst].suc[c] = u;
           if(lst == -1) nd[u].pre = rt, nd[u].c = str[i] - 'a';
           else
           {
               int p = nd[lst].suc[c];
               if(nd[p].len == nd[lst].len + 1) nd[u].pre = p, nd[u].c = str[i + nd[p].len] - 'a';
               else
               {
                   int q = tp ++;
                   memcpy(nd[q].suc, nd[p].suc, sizeof(nd[p].suc)); nd[q].pre = nd[p].pre; nd[q].len = nd[lst].len + 1; nd[q].endPosition = i;
                   // we must set nd[q].endPosition's value right now, 'cause it may be used later
                   nd[q].c = str[i + nd[nd[q].pre].len] - 'a';
                   nd[p].pre = nd[u].pre = q;
                   nd[p].c = str[nd[p].endPosition + nd[q].len] - 'a'; nd[u].c = str[i + nd[q].len] - 'a';
                   for(; ~ lst && nd[lst].suc[c] == p; lst = nd[lst].pre) nd[lst].suc[c] = q;
               }
           }
           lst = u;
       }
       DFS(rt);
       clk = 0; getId(rt);
       sum[0] = sz[0]; for(int i = 1; i < tp; ++ i) sum[i] = sum[i - 1] + sz[i];
   }
   inline void query(long long k)
   {
       k = (long long)(L ^ R ^ k) + 1;
       // int k = v;
       int curL = 0, curR = tp - 1, pos = -1;
       while(curL <= curR)
       {
           int mid = curL + curR >> 1;
           if(sum[mid] >= k) {pos = mid; curR = mid - 1;} else curL = mid + 1;
       }
       if(pos == -1) {L = 0; R = 0; printf("%d %d\n", L, R); return;}
       L = nd[idx[pos]].endPosition + 1; R = L + (k - sum[pos - 1] + nd[nd[idx[pos]].pre].len) - 1;
       printf("%d %d\n", L, R);
   }
}SAM;
int main()
{
 
#ifndef ONLINE_JUDGE
 
   freopen("string.in", "r", stdin);
   freopen("string.out", "w", stdout);
 
#endif
 
   static char str[LEN]; scanf("%s", str);
   SAM.build(str, strlen(str));
   int m; scanf("%d", &m);
   long long v;
   for(int i = 0; i < m; ++ i) scanf("%lld", &v), SAM.query(v);
}
posted @ 2017-09-07 15:59  Zeonfai  阅读(197)  评论(0编辑  收藏  举报