CF916E Jamie and Tree 题解
CF916E Jamie and Tree 题解
CF916E Jamie and Tree
题意
有一棵 个节点的有根树,标号为 ,你需要维护以下三种操作
-
给一个点 ,将整颗树的根变为 。
-
给两个点 ,将 所在的子树都加上 。
-
给一个点 ,问以 所在的子树的权值和。
分析
换根树剖板子题。设当前根为 ,有几种简单操作:
换根后 LCA
直接分讨即可。
int LCA(int x,int y)
{
if(dep[x]>dep[y]) swap(x,y);
int xr=lca(x,rt),yr=lca(y,rt),xy=lca(x,y);
if(xy==x)
{
if(xr==x){if(yr==y) return y;return yr;}
return x;
}
if(xr==x) return x;if(yr==y) return y;
if((xr==rt&&xy==yr)||(yr==rt&&xy==xr)) return rt;
if(xr==yr) return xy;
if(xy!=xr) return xr;return yr;
}
换根后子树修改
分几种情况讨论:
- 是
此时直接把所有点权都加上 。
- 不是 的祖先
此时情况如图所示,不难发现,无论 在哪, 的子树都不变。
- 是 的祖先
此时情况如图所示,设 为是 祖先的 的子节点,要想得到 ,我们可以每次把 向上跳重链,直到跳到 的子节点。可以发现,加的部分相当于整棵树刨掉 的子树,由于树剖之后子树内节点编号连续,所以可以用线段树区间修改,每次修改 。
此部分代码如下:
int get(int x,int y)
{
int fx=top[x],fy=top[y];
while(top[x]!=top[y])
{
if(dep[fx]<dep[fy]) swap(fx,fy),swap(x,y); //跳重链顶深度更深的
if(fa[fx]==y) return fx; //已经找到了
x=fa[fx],fx=top[x];
}
if(dep[x]>dep[y]) swap(x,y);
return hson[x];
}
void update_subtree(int u,int k)
{
if(u==rt) update(1,1,n,1,n,k); //对应情况1
else if(lca(u,rt)!=u) update(1,1,n,id[u],id[u]+cnt[u]-1,k); //情况2
else //情况3
{
int v=get(u,rt);
if(id[v]-1>=1) update(1,1,n,1,id[v]-1,k);
if(id[v]+cnt[v]<=n) update(1,1,n,id[v]+cnt[v],n,k);
}
}
换根后子树求和
原理和子树修改相同。
int query_subtree(int u)
{
int res=0;
if(u==rt) res=query(1,1,n,1,n);
else if(lca(u,rt)!=u) res=query(1,1,n,id[u],id[u]+cnt[u]-1);
else
{
int v=get(u,rt);
if(id[v]-1>=1) res+=query(1,1,n,1,id[v]-1);
if(id[v]+cnt[v]<=n) res+=query(1,1,n,id[v]+cnt[v],n);
}
return res;
}
完整代码
本文作者:l_x_y
本文链接:https://www.cnblogs.com/lxy-2022/p/CF916E-Solution.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步