【JZOJ4427/HNOI2016模拟】 Alphadog

【JZOJ4427/HNOI2016模拟】 Alphadog

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

题面:


每次在字符串后插入一个字符,并在线查询当前每个前缀前缀与其前面的每个前缀的最长公共回文后缀长度之和( LCP )。

1.

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

2.

然而这样太暴力,我们不妨考虑当前最长回文后缀对应节点 p 的每一个祖先对答案的贡献,那么得到下式:
Δans=Σyplen(y)(siz(y)siz(x)),xyxp
至此,维护 siz ,我们可拿到四十分。

3.

接下来该上大杀器—— LCT 了。转换上式可得:
Δans=Σypsiz(y)(len(y)len(father(y)))
由于 右边是一个常量,而左边每次只有一条链被修改,显然access(p)+lazytag就可以 logn 维护了。

#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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值