【JZOJ4427/HNOI2016模拟】 Alphadog

【JZOJ4427/HNOI2016模拟】 Alphadog

多么妙的一道LPT(Link-Palindromic-Tree)啊

题面:


<script type="math/tex" id="MathJax-Element-1">\;\;\;\;</script>每次在字符串后插入一个字符,并在线查询当前每个前缀前缀与其前面的每个前缀的最长公共回文后缀长度之和( LCP <script type="math/tex" id="MathJax-Element-2">LCP</script>)。

1. <script type="math/tex" id="MathJax-Element-3">1.</script>

<script type="math/tex" id="MathJax-Element-4">\;\;\;\;</script>除了因丧病的GDKOI而出名的 manacher <script type="math/tex" id="MathJax-Element-5">manacher</script>我们的cty拼错了算法外,还有一种更为强力的字符串回文子串处理工具——回文树 PalindromicTree <script type="math/tex" id="MathJax-Element-6">Palindromic-Tree</script>。这种妙不可言的数据结构能够匹配当前字符串的每一个回文子串。由于顺着失配边能够从长到短枚举当前位置的每一个回文后缀,所以两个前缀的 LCP <script type="math/tex" id="MathJax-Element-7">LCP</script>就是他们在 PT <script type="math/tex" id="MathJax-Element-8">PT</script>中对应的节点在失配树上的 LCA <script type="math/tex" id="MathJax-Element-9">LCA</script>。那么利用这个性质,我们大概能拿到二三十的暴力分。

2. <script type="math/tex" id="MathJax-Element-10">2.</script>

<script type="math/tex" id="MathJax-Element-11">\;\;\;\;</script>然而这样太暴力,我们不妨考虑当前最长回文后缀对应节点 p <script type="math/tex" id="MathJax-Element-12">p</script>的每一个祖先对答案的贡献,那么得到下式:
Δans=Σyplen(y)(siz(y)siz(x)),xyxp <script type="math/tex" id="MathJax-Element-13">\;\;\;\;\Delta ans=\Sigma_{y为p的祖先} len(y)*(siz(y)-siz(x)), x为y的儿子\wedge x为p的祖先</script>
至此,维护 siz <script type="math/tex" id="MathJax-Element-14">siz</script>,我们可拿到四十分。

3. <script type="math/tex" id="MathJax-Element-15">3.</script>

<script type="math/tex" id="MathJax-Element-16">\;\;\;\;</script>接下来该上大杀器—— LCT <script type="math/tex" id="MathJax-Element-17">LCT</script>了。转换上式可得:
Δans=Σypsiz(y)(len(y)len(father(y))) <script type="math/tex" id="MathJax-Element-18">\;\;\;\;\Delta ans=\Sigma_{y为p的祖先} siz(y)*(len(y)-len(father(y)))</script>
由于 <script type="math/tex" id="MathJax-Element-19">*</script>右边是一个常量,而左边每次只有一条链被修改,显然 access(p)+lazytag <script type="math/tex" id="MathJax-Element-20">access(p)+lazy\;tag</script>就可以 logn <script type="math/tex" id="MathJax-Element-21">log n</script>维护了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define re_ return
#define in_ inline
#define op_ operator
#define co_ const
#define ct_ continue
#define st_ static
#define ns_ namespace
#define un_ using ns_
#define br_ break
#define inc(l, i, r) for(i=l; i<r; ++i)
#define dec(r, i, l) for(i=r; i>l; --i)
typedef long long ll;

co_ ll mxn=200010;
ll n;

struct io
{
    in_ io& op_& (ll& a)
    {
        st_ ll c;
        for(a=0; (c=getchar())<48||57<c;);
        for(;c>47&&58>c; c=getchar())
            a=10*a+c-48;
        re_ *this;
    }
    in_ io& op_| (ll a)
        {re_ printf("%I64d\n", a), *this;}
    in_ io& op_^ (ll a)
        {re_ printf("%I64d", a), *this;}
    in_ io& op_^ (char* a)
        {re_ printf("%s", a), *this;}
} io;

ns_ lct
{
    ll f[mxn], s[mxn][2], a[mxn][2], b[mxn][2], t[mxn];
    #define sum(a) (u[s][0]a+u[s][1]a)
    in_ ll nw(ll u, ll x) {b[u][0]=b[u][1]=x;}
    in_ ll isroot(ll u)
        {re_ !u[f]||u[f][s][0]^u&&u[f][s][1]^u;}
    in_ ll upd(ll u)
    {
        u[a][1]=sum([a][1])+u[a][0],
        u[b][1]=sum([b][1])+u[b][0];
    }
    in_ ll plus(ll u, ll x)
    {
        u[t]+=x,
        u[a][0]+=x*u[b][0],
        u[a][1]+=x*u[b][1];
    }
    in_ ll push(ll u)
    {
        u[t]&&
        (
            plus(u[s][0], u[t]),
            plus(u[s][1], u[t]),
            u[t]=0
        );
    }
    in_ ll rotate(ll u)
    {
        st_ ll v, w, k;
        k=s[v=u[f]][1]==u, w=u[f]=v[f],
        !isroot(v)?w[s][w[s][1]==v]=u:0,
        f[v[s][k]=u[s][!k]]=v,
        f[u[s][!k]=v]=u,
        upd(v), upd(u);
    }
    in_ ll splay(ll u)
    {
        st_ ll v, q[mxn];
        for(v=0; ;u=u[f])
            if(isroot(q[v++]=u)) br_;
        for(;v;) push(q[--v]);
        for(u=q[0]; !isroot(u); rotate(u))
            if(
                !isroot(v=u[f])&&
                !(v[f][s][0]==v^v[s][0]==u)
            )
            rotate(v);
    }
    in_ ll access(ll u)
    {
        st_ ll v;
        for(v=0; u; v=u, u=u[f])
            splay(u), u[s][1]=v, upd(u);
    }
    in_ ll add(ll u)
    {
        access(u), splay(u), plus(u, 1);
    }
    in_ ll qry(ll u)
    {
        re_ access(u), splay(u), u[a][1];
    }
}

ns_ pam
{
    ll n, m, ed, str[mxn], f[mxn], s[mxn][26], l[mxn], c[mxn];
    in_ ll init()
    {
        str[0]=-1, m=2, l[1]=-1,
        lct::f[2]=f[ed=m=2]=f[1]=1,
        lct::nw(1,  -1), lct::nw(2, 1);
    }
    in_ ll get(ll u)
        {for(;str[n-u[l]-1]^str[n]; u=u[f]); re_ u;}
    in_ ll chk()
    {
    }
    in_ ll ins(ll x)
    {
        st_ ll u, v, w;
        str[++n]=x, u=get(ed);
        if(!u[s][x])
            u[s][x]=v=++m, v[l]=u[l]+2,
            v[lct::f]=v[f]=u^1?get(u[f])[s][x]:2,
            lct::nw(v, v[l]-v[f][l]);
        ed=v=u[s][x];
        lct::add(v);
        chk();
    }
    in_ ll qry()
    {
        st_ ll u, ans=0;
        ans+=lct::qry(ed);
        re_ ans;
    }
}


int main()
{
    freopen("alphadog5.in", "r", stdin);
//  freopen("2.out", "w", stdout);
    ll sig, lstan=0, i, x;
    io&n&sig, pam::init();
    inc(0, i, n)
    {
        io&x, sig?x^=lstan:0;
        pam::ins(x),
        x=pam::qry(),
        io|x, sig?lstan=x:0;
    }
    re_ 0;
}
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页