前缀和后缀方法差不多,但是没想的tarjan在线求LCA会超时,原来还有树链剖分这个神奇的东西,学到了
#include <stdio.h> #include <vector> #include <string.h> #include <algorithm> using namespace std; typedef long long ll; const int MAXN = 100010; char s[MAXN], cs[MAXN]; #ifndef __GNUC__ #pragma comment(linker, "/STACK:1024000000,1024000000") #endif // __GNUC__ struct node { node*nxt[26], *fa; int step, ln; void clear() { fa = 0, step = 0; memset ( nxt, 0, sizeof nxt ); } } *root, *tail, nodePool[MAXN << 1], *cur, *mseq[MAXN]; void init() { cur = nodePool; root = tail = cur++; root->clear(); mseq[0] = root; } void Insert ( int w ) { node *p = tail, *np = cur++; np->clear(); np->step = p->step + 1; mseq[np->step] = np; for ( ; p && !p->nxt[w]; p = p->fa ) { p->nxt[w] = np; } if ( !p ) { np->fa = root; } else { if ( p->nxt[w]->step == p->step + 1 ) { np->fa = p->nxt[w]; } else { node *q = p->nxt[w], *r = cur++; *r = *q; r->step = p->step + 1; q->fa = np->fa = r; for ( ; p && p->nxt[w] == q; p = p->fa ) { p->nxt[w] = r; } } } tail = np; } struct _edge { int v, next; }edge[MAXN<<2]; int head[MAXN<<1], mcnt; void add(int u, int v) { edge[mcnt].v = v; edge[mcnt].next = head[u]; head[u] = mcnt++; } int siz[MAXN<<1], fa[MAXN<<1], son[MAXN<<1], dep[MAXN<<1]; void dfs1(int u, int pre) { siz[u] = 1; fa[u] = pre; son[u] = 0; dep[u] = dep[pre] +1; for (int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].v; if (v == pre) continue; dfs1(v, u); siz[u] += siz[v]; if (siz[son[u]] < siz[v]) son[u] = v; } } int top[MAXN<<1]; void dfs2(int u, int pp) { top[u] = pp; if (son[u]) dfs2(son[u], top[u]); for (int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].v; if (v != fa[u] && v != son[u]) dfs2(v, v); } } void solve() { mcnt = 0; memset(head, -1, sizeof head); siz[0] = 0, fa[0] = 0; dep[0] = 0, son[0] = 0; for (node *p = nodePool+1; p < cur; ++p) add(p->fa - nodePool +1, 1+p - nodePool); dfs1(1, 0); dfs2(1, 1); } int getLCA ( int a, int b ) { while (1) { if (top[a] == top[b]) return dep[a]<dep[b]?a:b; else if (dep[top[a]] > dep[top[b]]) a = fa[top[a]]; else b = fa[top[b]]; } } ll res, all; int main() { #ifdef __GNUC__ freopen ( "in.txt", "r", stdin ); #endif // __GNUC__ int n, i, j, l, r, len; int tpl, bfl; char *p; node *nd, *lnd; while ( scanf ( "%s", s ) != EOF ) { for ( len = strlen ( s ), i = len - 1, j = 0; i >= 0; --i, ++j ) { cs[j] = s[i]; } cs[j] = 0; init(); for ( p = cs; *p; ++p ) { Insert ( *p - 'a' ); } solve(); scanf ( "%d", &n ); tpl = 0; res = 0; all = n; bfl = 10000000; lnd = root; while ( n-- ) { scanf ( "%d%d", &l, &r ); r--; l = len - l - 1; r = len - r - 1; swap ( l, r ); tpl = r - l + 1; all += tpl; nd = mseq[r + 1]; int tpnode = getLCA ( lnd-root+1, nd-root+1); int caoni = min ( min ( tpl, bfl ), nodePool[tpnode-1].step ); res -= caoni; for ( i = 0; caoni; i++, caoni /= 10 ); i += i == 0; res += i + 1; lnd = nd; bfl = tpl; } res = all + res; #ifdef __GNUC__ printf ( "%lld %lld\n", all, res ); #else printf ( "%I64d %I64d\n", all, res ); #endif } return 0; }