SP14943 DRTREE - Dynamically-Rooted Tree 题解
前置知识
解法
树剖换根,子树查询板子。
类似 换根 DP 的思路,我们发现换根后仅有祖先、子树、深度等会随祖先的变化而变化。
设 \(rt_{i}\) 表示第 \(i\) 次操作的树根,\(x_{i}\) 表示第 \(i\) 次操作的节点。接着进行大力分讨。
- 当 \(rt_{i}=x_{i}\) 时,等价于查询整棵树。
- 当 \(rt_{i} \ne x_{i}\) 且 \(rt_{i}\) 不在以 \(1\) 为根时以 \(x_{i}\) 为根的子树内,换根对其没有影响,等价于查询以 \(1\) 为根时以 \(x\) 为根的子树。
- 当 \(rt_{i} \ne x_{i}\) 且 \(rt_{i}\) 在以 \(1\) 为根时以 \(x_{i}\) 为根的子树内,换根对其产生影响,等价于查询整棵树除了以 \(1\) 为根时以 \(x\) 为根的子树中 \(rt_{i}\) 所在的方向的子树。可以分别求出后相减,也可以拆成两段区间求和。
- 现在问题成了如何求一个 \(y\) 使得 \(\begin{cases} y \in Son(x) \\ rt_{i} \in Subtree(y) \end{cases}\)。
- 对于节点 \(x,rt_{i}\) 不断向上跳重链,若不在同一条重链上时就已经满足条件则直接返回;否则,当跳到同一条重链上时,深度较小的节点的重儿子即为 \(y\)。
- 现在问题成了如何求一个 \(y\) 使得 \(\begin{cases} y \in Son(x) \\ rt_{i} \in Subtree(y) \end{cases}\)。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define sort stable_sort
#define endl '\n'
struct node
{
ll nxt,to;
}e[200010];
ll head[200010],c[200010],cc[200010],siz[200010],fa[200010],dep[200010],son[200010],top[200010],dfn[200010],out[200010],cnt=0,tot=0;
struct SegmentTree
{
ll l,r,sum;
}tree[800010];
ll lson(ll x)
{
return x*2;
}
ll rson(ll x)
{
return x*2+1;
}
void pushup(ll rt)
{
tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum;
}
void build(ll rt,ll l,ll r)
{
tree[rt].l=l;
tree[rt].r=r;
if(l==r)
{
tree[rt].sum=cc[l];
return;
}
ll mid=(l+r)/2;
build(lson(rt),l,mid);
build(rson(rt),mid+1,r);
pushup(rt);
}
ll query(ll rt,ll x,ll y)
{
if(x<=tree[rt].l&&tree[rt].r<=y)
{
return tree[rt].sum;
}
ll mid=(tree[rt].l+tree[rt].r)/2,ans=0;
if(x<=mid)
{
ans+=query(lson(rt),x,y);
}
if(y>mid)
{
ans+=query(rson(rt),x,y);
}
return ans;
}
void add(ll u,ll v)
{
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
void dfs1(ll x,ll father)
{
siz[x]=1;
fa[x]=father;
dep[x]=dep[father]+1;
for(ll i=head[x];i!=0;i=e[i].nxt)
{
if(e[i].to!=father)
{
dfs1(e[i].to,x);
siz[x]+=siz[e[i].to];
son[x]=(siz[e[i].to]>siz[son[x]])?e[i].to:son[x];
}
}
}
void dfs2(ll x,ll father,ll id)
{
top[x]=id;
tot++;
dfn[x]=tot;
cc[tot]=c[x];
if(son[x]!=0)
{
dfs2(son[x],x,id);
for(ll i=head[x];i!=0;i=e[i].nxt)
{
if(e[i].to!=father&&e[i].to!=son[x])
{
dfs2(e[i].to,x,e[i].to);
}
}
}
out[x]=tot;
}
ll dirson(ll u,ll v)
{
if(dep[u]>dep[v])
{
swap(u,v);
}
while(top[u]!=top[v])
{
if(dep[top[u]]>dep[top[v]])
{
if(fa[top[u]]==v)
{
return top[u];
}
u=fa[top[u]];
}
else
{
if(fa[top[v]]==u)
{
return top[v];
}
v=fa[top[v]];
}
}
return (dep[u]<dep[v])?son[u]:son[v];
}
ll query1(ll pos)
{
return query(1,dfn[pos],out[pos]);
}
ll query_reroot1(ll x,ll rt)
{
if(x==rt)
{
return query1(1);
}
else
{
if(dfn[x]<=dfn[rt]&&dfn[rt]<=out[x])
{
return query1(1)-query1(dirson(x,rt));
}
else
{
return query1(x);
}
}
}
int main()
{
ll n,m,u,v,rt=1,i;
char pd;
cin>>n;
for(i=1;i<=n;i++)
{
cin>>c[i];
}
for(i=2;i<=n;i++)
{
cin>>u;
v=i;
add(u,v);
add(v,u);
}
dfs1(1,0);
dfs2(1,0,1);
build(1,1,n);
cin>>m;
for(i=1;i<=m;i++)
{
cin>>pd;
if(pd=='S')
{
cin>>u;
cout<<query_reroot1(u,rt)<<endl;
}
else
{
cin>>rt;
}
}
return 0;
}
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18213443,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。