hdu 4691 Front compression(树连剖分)


前缀和后缀方法差不多,但是没想的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;
}

你可能感兴趣的:(hdu 4691 Front compression(树连剖分))