【JZOJ4427/HNOI2016模拟】 Alphadog
多么妙的一道LPT(Link-Palindromic-Tree)啊
题面:
每次在字符串后插入一个字符,并在线查询当前每个前缀前缀与其前面的每个前缀的最长公共回文后缀长度之和(
LCP
)。
1.
除了因丧病的GDKOI而出名的
manacher
我们的cty拼错了算法外,还有一种更为强力的字符串回文子串处理工具——回文树
Palindromic−Tree
。这种妙不可言的数据结构能够匹配当前字符串的每一个回文子串。由于顺着失配边能够从长到短枚举当前位置的每一个回文后缀,所以两个前缀的
LCP
就是他们在
PT
中对应的节点在失配树上的
LCA
。那么利用这个性质,我们大概能拿到二三十的暴力分。
2.
然而这样太暴力,我们不妨考虑当前最长回文后缀对应节点
p
的每一个祖先对答案的贡献,那么得到下式:
至此,维护
siz
,我们可拿到四十分。
3.
接下来该上大杀器——
LCT
了。转换上式可得:
Δans=Σy为p的祖先siz(y)∗(len(y)−len(father(y)))
由于
∗
右边是一个常量,而左边每次只有一条链被修改,显然
#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;
}