bzoj1396 识别子串

有个双倍经验2865,我T + RE + MLE......

然而...这个蓝色的背景是怎么回事...

线段树 + SAM。

考虑SAM的每个节点,显然只有cnt == 1的节点有贡献。因为cnt = 1所有只有一个right集合。于是其中比len[fail]短的备选答案就是lenfail +1,其余的备选答案就依次增长。

因为李超树很毒瘤就换个方式,发现斜率只可能是-1,于是维护真实值 + i的值。

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 
  5 const int M = 800010, N = 500010;
  6 
  7 int tr[M][26], len[M], fail[M], cnt[M], bin[M], topo[M], tot, last, right[M];
  8 char str[N];
  9 int small[N * 4], tag[N * 4], n;
 10 
 11 inline void init() {
 12     last = tot = 1;
 13     return;
 14 }
 15 
 16 inline void insert(char c, int id) {
 17     int f = c - 'a', p = last, np = ++tot;
 18     last = np;
 19     len[np] = len[p] + 1;
 20     cnt[np] = 1;
 21     right[np] = id;
 22     while(p && !tr[p][f]) {
 23         tr[p][f] = np;
 24         p = fail[p];
 25     }
 26     if(!p) {
 27         fail[np] = 1;
 28     }
 29     else {
 30         int Q = tr[p][f];
 31         if(len[Q] == len[p] + 1) {
 32             fail[np] = Q;
 33         }
 34         else {
 35             int nQ = ++tot;
 36             len[nQ] = len[p] + 1;
 37             fail[nQ] = fail[Q];
 38             fail[Q] = fail[np] = nQ;
 39             memcpy(tr[nQ], tr[Q], sizeof(tr[Q]));
 40             while(tr[p][f] == Q) {
 41                 tr[p][f] = nQ;
 42                 p = fail[p];
 43             }
 44         }
 45     }
 46     return;
 47 }
 48 
 49 void changeMin(int L, int R, int v, int l, int r, int o) {
 50     if(L <= l && r <= R) {
 51         small[o] = std::min(small[o], v);
 52         return;
 53     }
 54     int mid = (l + r) >> 1;
 55     if(L <= mid) changeMin(L, R, v, l, mid, o << 1);
 56     if(mid < R) changeMin(L, R, v, mid + 1, r, o << 1 | 1);
 57     return;
 58 }
 59 
 60 void change(int L, int R, int v, int l, int r, int o) {
 61     if(L <= l && r <= R) {
 62         tag[o] = std::min(tag[o], v);
 63         return;
 64     }
 65     int mid = (l + r) >> 1;
 66     if(L <= mid) change(L, R, v, l, mid, o << 1);
 67     if(mid < R) change(L, R, v, mid + 1, r, o << 1 | 1);
 68     return;
 69 }
 70 
 71 inline void sort() {
 72     for(int i = 1; i <= tot; i++) {
 73         bin[len[i]]++;
 74     }
 75     for(int i = 1; i <= tot; i++) {
 76         bin[i] += bin[i - 1];
 77     }
 78     for(int i = 1; i <= tot; i++) {
 79         topo[bin[len[i]]--] = i;
 80     }
 81     for(int i = tot; i >= 2; i--) {
 82         int x = topo[i];
 83         if(cnt[x] == 1) {
 84             changeMin(right[x] - len[fail[x]], right[x], len[fail[x]] + 1, 1, n, 1);
 85             if(len[fail[x]] < len[x] - 1) change(right[x] - len[x] + 1, right[x] - len[fail[x]] - 1, right[x] + 1, 1, n ,1);
 86             //printf("change Min %d %d %d \n", right[x] - len[fail[x]], right[x], len[fail[x]] + 1);
 87             //printf("change %d %d %d \n", right[x] - len[x] + 1, right[x] - len[fail[x]] - 1, right[x] + 1);
 88         }
 89         cnt[fail[x]] += cnt[x];
 90         right[fail[x]] = right[x];
 91     }
 92     return;
 93 }
 94 
 95 inline void Min(int &a, int b) {
 96     a > b ? a = b : 0;
 97     return;
 98 }
 99 
100 void cal(int l, int r, int o) {
101     if(l == r) {
102         printf("%d\n", std::min(small[o], tag[o] - r));
103         return;
104     }
105     int ls = o << 1, rs = ls | 1;
106     Min(small[o << 1], small[o]);
107     Min(tag[o << 1], tag[o]);
108     Min(small[o << 1 | 1], small[o]);
109     Min(tag[o << 1 | 1], tag[o]);
110     int mid = (l + r) >> 1;
111     cal(l, mid, o << 1);
112     cal(mid + 1, r, o << 1 | 1);
113     return;
114 }
115 
116 int main() {
117     memset(tag, 0x3f, sizeof(tag));
118     memset(small, 0x3f, sizeof(small));
119     init();
120     scanf("%s", str);
121     n = strlen(str);
122     for(int i = 0; i < n; i++) {
123         insert(str[i], i + 1);
124     }
125     sort();
126     cal(1, n, 1);
127     return 0;
128 }
AC代码

 

posted @ 2019-03-05 17:57  huyufeifei  阅读(153)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜