DRTREE - Dynamically-Rooted Tree

本题建议评蓝。

思路:

题目就是要对一颗不定根树求子树权值和。

这题不带修,如果带修难度会增加一点,就跟 遥远的国度 差不多。

首先分析一下在以不同根下子树的变化。

当一颗树以 1 号节点为根时,比如说长这样:

假设每个点的权值为 1,那么这 8 个点的子树权值和(在这里也是子树大小)分别为:8,2,4,1,1,1,1,1。这是可以通过预处理得到的。

而当整个树的根变化后,我们分情况讨论:(假设变化后的根为 \(A\),要求的点为 \(B\))

  • 当 \(A=B\) 时,毫无疑问答案是整个树的权值和。

  • 当 \(A\) 不在 \(B\) 的子树中时,我们发现,\(B\) 的子树不会发生变化,那么子树权值和也就是在以 1 为根的情况下的权值和。

  • 当 \(A\) 在 \(B\) 的子树中时,情况复杂起来了。举个例子,比如说在上图中,将根换成 8 号节点,求 3 号节点:

我们可以发现,这时的 3 号节点的子树权值和变成了:树的权值总和减去 3 号点在 8 号点方向的子树的权值和。(这个例子可能不太好,可以自己画几个图模拟一下。)

因此我们可以得出结论:在这种情况下,答案就是树的权值和减去 \(B\) 在 \(A\) 方向上的子树的权值和。

还剩下几个问题:

怎么判断一个点 \(A\) 是不是在另一个点 \(B\) 的子树中?

方法很多,有的简单有的相对麻烦。

比如说求 \(A\),\(B\) 的 \(\text{LCA}\) ,看看是不是 \(B\),时间复杂度为 \(O(\log n)\)。

再比如说用树剖加线段树,将 \(B\) 的“权值”设为 \(1\) ,其他的点设为 \(0\),判断从点

\(A\) 到 \(1\) 的路径上的“权值”最大值是不是 \(1\),时间复杂度为 \(O(\log ^2n)\)。

这里我们使用了最简单也是最快的方法,利用 \(\text{dfs}\) 序进行判断。

(我们用 \(\text{dfn}\) 表示 \(\text{dfs}\) 序,\(\text{size}\) 表示子树大小。)

因为当且仅当 \(\text{dfn}[B]\le \text{dfn}[A] \le \text{dfn}[B]+\text{size}[B]-1\) 时,点 \(A\) 会在 \(B\) 的子树中,故可以通过这个式子进行判断,时间复杂度为 \(O(1)\)。

怎么求一个点 \(A\) 在 另一个点 \(B\) 的方向上的子树权值和?(点 \(B\) 在 \(A\) 的子树内)

因为我们预处理了子树权值和,所以我们只需要求出点 \(A\) 在点 \(B\) 方向上的儿子就可以了。

我们可以用树剖解决这个问题(当然,倍增也可以,但更慢。):

我们按链一段段跳,如果跳的途中发现某点所在的链顶的父亲是另一个点,那么返回链顶。如果一直跳到了最后,因为此时两点在同一条链上,所以这时返回深度较小的点的重儿子就行了。

int lcason(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) Swap(x,y);
if(fa[top[x]]==y) return top[x];
x=fa[top[x]];
}
if(dep[x]>dep[y]) Swap(x,y);
return son[x];
}

注意事项:

加边方式比较奇怪,注意一下。

点权较大,记得开 long long 。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=200100;
typedef long long ll; int to[N],nxt[N],head[N],w[N];//链星
int dfn[N],siz[N],top[N],dep[N],son[N],fa[N],rnk[N];//树剖
int idx,n,q,in1,cnt,rt=1;
ll W[N],sum,ans;//W表示子树权值和
char op[2]; void add(int u,int v){idx++;to[idx]=v;nxt[idx]=head[u];head[u]=idx;}
void Swap(int &x,int &y){int t=x;x=y;y=t;} void dfs_1(int s,int gr){
siz[s]=1;son[s]=-1;fa[s]=gr;
dep[s]=dep[gr]+1;
W[s]=w[s];sum+=w[s];//预处理子树权值和
for(int i=head[s];i;i=nxt[i]){
int v=to[i];
if(v==gr) continue;
dfs_1(v,s);
siz[s]+=siz[v];W[s]+=W[v];
if(son[s]==-1||siz[v]>siz[son[s]]) son[s]=v;
}
} void dfs_2(int s,int tp){
top[s]=tp;dfn[s]=++cnt;rnk[cnt]=s;
if(son[s]==-1) return ;
dfs_2(son[s],tp);
for(int i=head[s];i;i=nxt[i]){
int v=to[i];
if(v==fa[s]||v==son[s]) continue;
dfs_2(v,v);
}
} int lcason(int x,int y){//求某点在另一个点方向上的儿子
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) Swap(x,y);
if(fa[top[x]]==y) return top[x];
x=fa[top[x]];
}
if(dep[x]>dep[y]) Swap(x,y);
return son[x];
} int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<n;i++){
scanf("%d",&in1);
add(in1,i+1);add(i+1,in1);//加边
}
dfs_1(1,0);dfs_2(1,1);//先以1为根跑树剖
scanf("%d",&q);
while(q--){
scanf("%s%d",op+1,&in1);
if(op[1]=='S'){
if(rt==in1) ans=sum;
else if(dfn[in1]<=dfn[rt]&&dfn[rt]<=dfn[in1]+siz[in1]-1) ans=sum-W[lcason(in1,rt)];
else ans=W[in1];//我们讨论过的三种情况
cout<<ans<<'\n';
}
if(op[1]=='R') rt=in1;
}
return 0;
}

其他:

类似的题目:

P3979 遥远的国度,

Jamie and Tree(这两个都带修)。

DRTREE - Dynamically-Rooted Tree 题解的更多相关文章

  1. hdu 1232, disjoint set, linked list vs. rooted tree, a minor but substantial optimization for path c 分类: hdoj 2015-07-16 17:13 116人阅读 评论(0) 收藏

    three version are provided. disjoint set, linked list version with weighted-union heuristic, rooted ...

  2. CF1153D Serval and Rooted Tree

    题目地址:CF1153D Serval and Rooted Tree 挺好玩儿也挺考思维的一道题 思路:树形DP+贪心 数组 \(d\) 维护这样一个值: 对于一个节点 \(x\) ,它的值最大可以 ...

  3. D. Serval and Rooted Tree (樹狀DP)

    Codeforce 1153D Serval and Rooted Tree (樹狀DP) 今天我們來看看CF1153D 題目連結 題目 給一棵數,假設有$k$個葉節點,我們可以給葉節點分配$1$~$ ...

  4. Codeforces Round #530 (Div. 2):D. Sum in the tree (题解)

    D. Sum in the tree 题目链接:https://codeforces.com/contest/1099/problem/D 题意: 给出一棵树,以及每个点的si,这里的si代表从i号结 ...

  5. POJ 1308 Is It A Tree?--题解报告

    Is It A Tree? Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 31092   Accepted: 10549 D ...

  6. C++版 - 剑指offer 面试题39:判断平衡二叉树(LeetCode 110. Balanced Binary Tree) 题解

    剑指offer 面试题39:判断平衡二叉树 提交网址:  http://www.nowcoder.com/practice/8b3b95850edb4115918ecebdf1b4d222?tpId= ...

  7. cf-Round551-Div2-D. Serval and Rooted Tree(DP)

    题目链接:https://codeforces.com/contest/1153/problem/D 题意:有一棵树,给定结点数n,在每个结点上的操作(max:表示该结点的number为其孩子结点中的 ...

  8. 【文文殿下】CF1098C Construct a tree 题解

    题解 挺水的一道题. Rating $ \color{orange} {2300}$ 以下送命题. 首先我们知道,所有子树大小之和就是节点个数加上从根到所有节点的路径长度之和. 他要求度数尽可能小,所 ...

  9. BZOJ2588:Count on a tree——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2588 Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你 ...

  10. CC TSUBSTR:Substrings on a Tree——题解

    https://www.codechef.com/problems/TSUBSTR https://vjudge.net/problem/CodeChef-TSUBSTR 给一棵点权为字母的树,你只能 ...

随机推荐

  1. Dubbo 我手写几行代码,就把通信模式给你解释清楚!

    作者:小傅哥 博客:https://bugstack.cn 原文:https://bugstack.cn/md/road-map/road-map.html 沉淀.分享.成长,让自己和他人都能有所收获 ...

  2. P3047 [USACO12FEB]Nearby Cows G 题解

    P3047 [USACO12FEB]Nearby Cows G 题目描述 思路 使用换根DP, 设 \(dp[i][j]\) 表示以 \(i\) 为根节点的子树中深度小于等于 \(j\) 的点的权值之 ...

  3. ISP图像处理——紫边Purple Fringing检测

    之前写过文章记紫边的形成原因,以下小结改善方法 图像紫边存在数码相机.监控摄像头等数字成像图像,使用设备在逆光.大光圈条件下拍摄图像的高反差区域容易出现紫边,解决图像自编问题有助设备得到完美图像. 紫 ...

  4. 2023年icpc大学生程序设计竞赛-crf

    第一次在除郑轻以外的校外的地方比赛,也是第一次出市比赛,赛程也比较长.20号出发的时候遇到一些意外,不过无伤大雅,第一天热身赛平平无奇,晚上的时候补了一下前年icpc的题,一个多小时做了五题,很是自信 ...

  5. Windows商店开发者注册失败

    前言 最近写了个小工具想上架Windows应用商店,但是在填写信息那一页总是失败,提示Error code 2201. Correlation ID 9d436e3a-94df-498a-b224-8 ...

  6. python安装后pip用不了 cmd命令窗口提示:Did not provide a command

    遇到的问题: 解决方法: 首先,使用where pip找到我的pip的安装目录 其次,配置环境变量 环境变量已经配置,但是仍是使用的时候直接输入pip提示"Did not provide a ...

  7. 如何编写难以维护的React代码?——滥用useEffect

    如何编写难以维护的React代码?--滥用useEffect 在许多项目中,我们经常会遇到一些难以维护的React代码.其中一种常见的情况是滥用useEffect钩子,特别是在处理衍生状态时.让我们来 ...

  8. Qt+GDAL开发笔记(二):在windows系统msvc207x64编译GDAL库、搭建开发环境和基础Demo

    前言   上一篇使用mingw32版本的gdal,过程曲折,为更好的更方便搭建环境,在windows上msvc方式对于库比较友好.   大地坐标简介 概述   大地坐标(Geodetic coordi ...

  9. 基于md5加密的模拟管理员登录系统

    import os import pandas as pd def md5(string:str=''):     import hashlib     md5 = hashlib.md5()     ...

  10. manacher(马拉车)算法C++详解

    马拉车的定义 马拉车本质是对中心扩展法(暴力算法)的优化. 马拉车是干什么的 Manacher算法帮助我们在给定的字符串中找到最长的回文子串. 为了简单起见,我们先只处理有奇数个字符的字符串,关于偶数 ...