题面

题解

我们求它子树的权值和,一般用dfs序把树拍到线段树上做。

当它换根时,我们就直接把root赋值就行了,树的结构不去动它。

对于第二个操作,我们得到的链和根的相对位置有三种情况:

设两点为A、B,LCA 为 C,一个点x的dfs序为ld[x],从它的子树里出来时的dfs序为rd[x]

第一种情况,根是C的祖先,他的实际操作区间就是原本的子树区间[ld[C],rd[C]]

第二种情况,根在A、B路径上,那么它的实际LCA就应该是root,操作区间为[1,n]

第三种情况,根在C的子树上,A、B路径外,那么我们实际上要找到红色路径上最上方的点D

点D的父亲刚好在A、B路径上,那么实际子树就是除了D子树外的其他部分,操作区间为[1,ld[D])∪(rd[D],n]

把相应区间在线段树上区间加就行了。

3操作就相当于A=B的路径。

CODE

#include<cstdio>
#include<cstring>
#include<iostream>
//-----------F1
using namespace std;
#include<algorithm>
#include<cmath>
//-----------F2
#include<vector>
#include<stack>
#include<queue>
#include<map>
#define MAXN 100005
#define LL long long
#define lowbit(x) (-(x) & (x))
#define ENDL putchar('\n')
//#pragma GCC optimize(2)
//#pragma G++ optimize(3)
//#define int LL
char char_read_before = 1;
inline int read() {
int f = 1,x = 0;char s = char_read_before;
while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
while(s >= '0' && s <= '9') {x = x * 10 - '0' + s;s = getchar();}
char_read_before = s;return x * f;
}
LL zxy = 1000000007ll; // 用来膜的
int n,m,i,j,s,o,k,root = 1;
LL a[MAXN],da[MAXN];
LL tre[MAXN<<2],lz[MAXN<<2],M;
inline void maketree(int n) {
M = 1; while(M < n+2) M <<= 1;
for(int i = 1;i <= n;i ++) {
tre[i + M] = da[i];
}
for(int i = M-1;i > 0;i --) {
tre[i] = tre[i<<1] + tre[i<<1|1];
}
}
inline void addtree(int l,int r,LL y) {
if(l > r) return ;
// printf("add %lld to [%d,%d]\n",y,l,r);
int s = M + l - 1,t = M + r + 1;
int ls = 0,rs = 0,sz = 1;
while(s || t) {
tre[s] += ls * y;
tre[t] += rs * y;
if((s>>1) ^ (t>>1)) {
if(!(s & 1)) tre[s^1] += y * sz,lz[s^1] += y,ls += sz;
if(t & 1) tre[t^1] += y * sz,lz[t^1] += y,rs += sz;
}
s >>= 1; t >>= 1; sz <<= 1;
}
return ;
}
inline LL findtree(int l,int r) {
if(l > r) return 0;
int s = M + l - 1,t = M + r + 1;
int ls = 0,rs = 0,sz = 1;
LL ans = 0;
while(s || t) {
ans += ls * lz[s];
ans += rs * lz[t];
if((s>>1) ^ (t>>1)) {
if(!(s & 1)) ans += tre[s^1],ls += sz;
if(t & 1) ans += tre[t^1],rs += sz;
}
s >>= 1; t >>= 1; sz <<= 1;
}
return ans;
}
vector<int> g[MAXN];
int dfn[MAXN],rd[MAXN],cnt;
int fa[MAXN][18],d[MAXN];
inline void dfs(int x,int fat) {
dfn[x] = ++ cnt;
da[cnt] = a[x];
fa[x][0] = fat;
d[x] = d[fat] + 1;
for(int i = 1;i <= 17;i ++) fa[x][i] = fa[fa[x][i-1]][i-1];
for(int i = 0;i < g[x].size();i ++) {
if(g[x][i] != fat) {
dfs(g[x][i],x);
}
}
rd[x] = cnt;
return ;
}
inline int lca(int a,int b) {
if(d[a] < d[b]) swap(a,b);
if(d[a] > d[b]) {
for(int i = 17;i >= 0;i --) {
if(d[fa[a][i]] >= d[b]) a = fa[a][i];
}
}
if(a == b) return a;
for(int i = 17;i >= 0;i --) {
if(fa[a][i] ^ fa[b][i]) {
a = fa[a][i];
b = fa[b][i];
}
}
return fa[a][0];
} signed main() {
n = read();m = read();
for(int i = 1;i <= n;i ++) {
a[i] = read();
}
for(int i = 2;i <= n;i ++) {
s = read();o = read();
g[s].push_back(o);
g[o].push_back(s);
}
dfs(1,0);
maketree(n);
for(int i = 1;i <= m;i ++) {
k = read();
if(k == 1) {
root = read();
}
else if(k == 2) {
s = read();o = read();k = read();
int lc = lca(s,o);
if(d[lca(root,lc)] < d[lc]) {
addtree(dfn[lc],rd[lc],(LL)k);
}
else if(lca(root,s) == root || lca(root,o) == root) {
addtree(1,n,(LL)k);
}
else {
int lt = lca(root,s),rt = lca(root,o);
int fn = root;
for(int i = 17;i >= 0;i --) {
if(d[fa[fn][i]] > max(d[lt],d[rt])) {
fn = fa[fn][i];
}
}
addtree(1,dfn[fn] - 1,(LL)k);
addtree(rd[fn] + 1,n,(LL)k);
}
}
else if(k == 3) {
s = read();
if(lca(s,root) ^ s) {
printf("%lld\n",findtree(dfn[s],rd[s]));
}
else if(s ^ root) {
int fn = root;
for(int i = 17;i >= 0;i --) {
if(d[fa[fn][i]] > d[s]) fn = fa[fn][i];
}
printf("%lld\n",findtree(1,dfn[fn] - 1) + findtree(rd[fn] + 1,n));
}
else printf("%lld\n",findtree(1,n));
}
}
return 0;
}

Jamie and Tree (dfs序 + 最近公共祖先LCA)的更多相关文章

  1. POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和)

    POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和) 题意分析 卡卡屋前有一株苹果树,每年秋天,树上长了许多苹果.卡卡很喜欢苹果.树上有N个节点,卡卡给他们编号1到N,根 ...

  2. POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)

    POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...

  3. POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)

    POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...

  4. [模板] 最近公共祖先/lca

    简介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点. 定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * ...

  5. Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)

    Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...

  6. 【lhyaaa】最近公共祖先LCA——倍增!!!

    高级的算法——倍增!!! 根据LCA的定义,我们可以知道假如有两个节点x和y,则LCA(x,y)是 x 到根的路 径与 y 到根的路径的交汇点,同时也是 x 和 y 之间所有路径中深度最小的节 点,所 ...

  7. leetcode 236. 二叉树的最近公共祖先LCA(后序遍历,回溯)

    LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 题目描述 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百 ...

  8. Codeforces Round #200 (Div. 1)D. Water Tree dfs序

    D. Water Tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/343/problem/ ...

  9. poj 3321 Apple Tree dfs序+线段树

    Apple Tree Time Limit: 2000MS   Memory Limit: 65536K       Description There is an apple tree outsid ...

随机推荐

  1. 优先队列STL

    引入 优先队列是一种特殊的队列,它的功能是--自动排序. 基本操作: q.size(); //返回q里元素个数 q.empty(); //返回q是否为空,空则返回1,否则返回0 q.push(k); ...

  2. Eureka属性配置

    一:Eureka Instance实例信息配置   里面的配置以"-"隔开 其实也支持驼峰命名代替"-" 首先是入门时的配置: server: port: 80 ...

  3. [pwn基础] Linux安全机制

    目录 [pwn基础] Linux安全机制 Canary(栈溢出保护) 开启关闭Cannary Canary的种类 Terminator canaries(终结者金丝雀) Random cannarie ...

  4. 送分题,ArrayList 的扩容机制了解吗?

    1. ArrayList 了解过吗?它是啥?有啥用? 众所周知,Java 集合框架拥有两大接口 Collection 和 Map,其中,Collection 麾下三生子 List.Set 和 Queu ...

  5. LVGL库入门教程 - 颜色和图像

    颜色 构造颜色 在 LVGL 中,颜色以结构 lv_color_t 表示.在最开始移植整个工程时,曾经在 lv_conf.h 中修改过颜色深度: /*Color depth: 1 (1 byte pe ...

  6. 期末人福音——用Python写个自动批改作业系统

    一.亮出效果 最近一些软件的搜题.智能批改类的功能要下线. 退1024步讲,要不要自己做一个自动批改的功能啊?万一哪天孩子要用呢! 昨晚我做了一个梦,梦见我实现了这个功能,如下图所示:功能简介:作对了 ...

  7. 动态树 — Link_Cut_Tree

    [模板]动态树(Link Cut Tree) Link-cut-tree是一种维护动态森林的数据结构,在需要动态加边/删边的时候就需要LCT来维护. Link-cut-tree的核心是轻重链划分,每条 ...

  8. idea 内置tomcat jersey 上传文件报403错误

    Request processing failed; nested exception is com.sun.jersey.api.client.UniformInterfaceException: ...

  9. SPFA算法(SLF优化)2022.7.8更新

    SPFA可能会被卡掉,能用dijkstra就别用SPFA,代码较长,但我已尽力做到解释,请耐心看下去,存储为邻接表存储. #include<bits/stdc++.h> #define i ...

  10. 基于二进制安装Cloudera Manager集群

    一.环境准备 参考链接:https://www.cnblogs.com/zhangzhide/p/11108472.html 二.安装jdk(三台主机都要做) 下载jdk安装包并解压:tar xvf ...