zoukankan      html  css  js  c++  java
  • 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 
    ", right[x] - len[fail[x]], right[x], len[fail[x]] + 1);
     87             //printf("change %d %d %d 
    ", 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
    ", 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代码
  • 相关阅读:
    Linux-Zabbix 邮件报警设置
    CentOS6.7 防火墙规则(Iptables)
    CentOS7 防火墙规则 (firewalld)
    windows搭建代理服务器
    Linux服务器的远程IP限制
    利用shell脚本监控目录内文件改动
    CentOS 7, 升级python到3.x
    CentOS 7, Attempting to create directory /root/perl5
    变长参数表
    C语言预处理
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10478502.html
Copyright © 2011-2022 走看看