E. Jamie and Tree
time limit per test

2.5 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

To your surprise, Jamie is the final boss! Ehehehe.

Jamie has given you a tree with n vertices, numbered from 1 to n. Initially, the root of the tree is the vertex with number 1. Also, each vertex has a value on it.

Jamie also gives you three types of queries on the tree:

v — Change the tree's root to vertex with number v.

u v x — For each vertex in the subtree of smallest size that contains u and v, add x to its value.

v — Find sum of values of vertices in the subtree of vertex with number v.

A subtree of vertex v is a set of vertices such that v lies on shortest path from this vertex to root of the tree. Pay attention that subtree of a vertex can change after changing the tree's root.

Show your strength in programming to Jamie by performing the queries accurately!

Input

The first line of input contains two space-separated integers n and q (1 ≤ n ≤ 105, 1 ≤ q ≤ 105) — the number of vertices in the tree and the number of queries to process respectively.

The second line contains n space-separated integers a1, a2, ..., an ( - 108 ≤ ai ≤ 108) — initial values of the vertices.

Next n - 1 lines contains two space-separated integers ui, vi (1 ≤ ui, vi ≤ n) describing edge between vertices ui and vi in the tree.

The following q lines describe the queries.

Each query has one of following formats depending on its type:

v (1 ≤ v ≤ n) for queries of the first type.

u v x (1 ≤ u, v ≤ n,  - 108 ≤ x ≤ 108) for queries of the second type.

v (1 ≤ v ≤ n) for queries of the third type.

All numbers in queries' descriptions are integers.

The queries must be carried out in the given order. It is guaranteed that the tree is valid.

Output

For each query of the third type, output the required answer. It is guaranteed that at least one query of the third type is given by Jamie.

Examples
input
6 7
1 4 2 8 5 7
1 2
3 1
4 3
4 5
3 6
3 1
2 4 6 3
3 4
1 6
2 2 4 -5
1 4
3 3
output
27
19
5
input
4 6
4 3 5 6
1 2
2 3
3 4
3 1
1 3
2 2 4 3
1 1
2 2 4 -3
3 1
output
18
21
Note

The following picture shows how the tree varies after the queries in the first sample.

大意:给出一颗树,初始根节点为1,三种操作:

1.把一个节点变成根节点

2.给出两个节点u,v,把包含这两个点的最小子树中每个节点权值加上x

3.查询以 u 为根的子树的权值和。

题解:

如果没有操作一,这题就是把LCA和dfs序列化以及线段树的板子放在一起。

但是,对于操作一,如何解决?

其实并不需要真的把节点提到根上。

我们可以一直以 1 为根节点,利用一些小结论来进行2和3操作。

假设在该图中,当前根节点为6,但是我们的dfs序列仍然是以1为根节点的。

如果当前根节点不在要修改(查询)的子树中,就没有任何影响,直接修改(查询)即可,此处不做讨论。

下面只说根节点在要修改(查询)的子树中的情况。

如果现在给出操作2,把包含2,4的最小子树上面的每个节点加delta。

我们应该处理的节点是 1 2 3 4 5

lca(2,4)=1     lca(2,6)=1    lca(4,6)=3

有一个大胆的猜想:

直接修改lca(2,4)=1的子树,然后把不该修改的哪部分改回去。

那么多修改的哪部分是那些呢:

大胆猜想:

取这三组lca中深度最大的那个(节点3)

当前的根节点6所在的     节点3的子树     就是多修改的那部分。

对于询问操作,思想大体相似

若当前根节点为6,询问1的子树的权值和。

先算上整颗树,然后减去多加的部分。

多加的部分就是根节点6所在的     节点1的子树,也就是3,4,5,6。

大胆猜想,不用证明,恩,这结论就是对的。

 /*
Welcome Hacking
Wish You High Rating
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<string>
using namespace std;
int read(){
int xx=,ff=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')ff=-;ch=getchar();}
while(ch>=''&&ch<=''){xx=(xx<<)+(xx<<)+ch-'';ch=getchar();}
return xx*ff;
}
const int maxn=;
int N,Q,opt,t1,t2,t3,root,v[maxn];
int tid[maxn],rk[maxn],tim,Prev[maxn],depth[maxn],end[maxn];
int lin[maxn],len;
struct edge{
int y,next;
}e[maxn<<];
inline void insert(int xx,int yy){
e[++len].next=lin[xx];
lin[xx]=len;
e[len].y=yy;
}
void dfs(int x,int prev){
depth[x]=depth[prev]+;
tid[x]=++tim;
rk[tim]=x;
Prev[x]=prev;
for(int i=lin[x];i;i=e[i].next)
if(e[i].y!=prev)
dfs(e[i].y,x);
end[x]=tim;
}
int f[][maxn];
int LCA(int x,int y){
if(depth[x]<depth[y])
swap(x,y);
int dif=depth[x]-depth[y];
for(int i=;i>=;i--)
if(dif&(<<i))
x=f[i][x];
if(x==y)
return x;
for(int i=;i>=;i--)
if(f[i][x]!=f[i][y])
x=f[i][x],y=f[i][y];
return f[][x];
}
int LCALCA(int x,int y){
int t1=LCA(x,y),t2=LCA(x,root),t3=LCA(y,root);
if(depth[t1]<depth[t2])
swap(t1,t2);
if(depth[t1]<depth[t3])
return t3;
return t1;
}
int get_son(int x){
int temp=root;
int dif=depth[root]-depth[x]-;
for(int i=;i>=;i--)
if(dif&(<<i))
temp=f[i][temp];
return temp;
}
struct Segment_Tree{
long long sum,tag;
}T[maxn<<];
int X,Y,Z;
void build(int L,int R,int root){
if(L==R){
T[root].sum=v[rk[L]];
return;
}
int mid=(L+R)>>;
build(L,mid,root<<);
build(mid+,R,root<<|);
T[root].sum=T[root<<].sum+T[root<<|].sum;
}
void upd(int L,int R,int root){
if(X>R||Y<L)
return;
if(X<=L&&Y>=R){
T[root].tag+=Z;
T[root].sum+=1LL*(R-L+)*Z;
return;
}
int mid=(L+R)>>;
if(T[root].tag){
T[root<<].tag+=T[root].tag;
T[root<<|].tag+=T[root].tag;
T[root<<].sum+=T[root].tag*(mid-L+);
T[root<<|].sum+=T[root].tag*(R-mid);
T[root].tag=;
}
upd(L,mid,root<<);
upd(mid+,R,root<<|);
T[root].sum=T[root<<].sum+T[root<<|].sum;
}
long long query(int L,int R,int root){
if(X>R||Y<L)
return ;
if(X<=L&&Y>=R)
return T[root].sum;
int mid=(L+R)>>;
if(T[root].tag){
T[root<<].tag+=T[root].tag;
T[root<<|].tag+=T[root].tag;
T[root<<].sum+=T[root].tag*(mid-L+);
T[root<<|].sum+=T[root].tag*(R-mid);
T[root].tag=;
}
return query(L,mid,root<<)+query(mid+,R,root<<|);
}
int main(){
//freopen("in.txt","r",stdin);
N=read(),Q=read();root=;
for(int i=;i<=N;i++)
v[i]=read();
for(int i=;i<N;i++){
t1=read(),t2=read();
insert(t1,t2);
insert(t2,t1);
}
dfs(,);
/*for(int i=1;i<=N;i++)
printf("%d ",tid[i]);
puts("");
for(int i=1;i<=N;i++)
printf("%d ",rk[i]);
puts("");
for(int i=1;i<=N;i++)
printf("%d ",depth[i]);
puts("");*/
build(,N,);
for(int i=;i<=N;i++)
f[][i]=Prev[i];
for(int i=;i<=;i++)
for(int j=;j<=N;j++)
f[i][j]=f[i-][f[i-][j]];
while(Q--){
opt=read();
if(opt==)
root=read();
else if(opt==){
t1=read(),t2=read(),t3=read();
int lca=LCALCA(t1,t2);
if(tid[root]>=tid[lca]&&tid[root]<=end[lca]){
X=,Y=N,Z=t3;
upd(,N,);
if(lca==root)
continue;
int temp=get_son(lca);
X=tid[temp],Y=end[temp],Z=-t3;
upd(,N,);
}
else{
X=tid[lca],Y=end[lca],Z=t3;
upd(,N,);
}
}
else{
int lca=read();
if(lca==root){
X=,Y=N;
printf("%I64d\n",query(,N,));
}
else if(tid[root]>=tid[lca]&&tid[root]<=end[lca]){
long long ans=;
X=,Y=N;
ans=query(,N,);
int temp=get_son(lca);
X=tid[temp],Y=end[temp];
ans-=query(,N,);
printf("%I64d\n",ans);
}
else{
X=tid[lca],Y=end[lca];
printf("%I64d\n",query(,N,));
}
}
}
return ;
}

codeforces 916E Jamie and Tree dfs序列化+线段树+LCA的更多相关文章

  1. CodeForces 620E:New Year Tree(dfs序+线段树)

    E. New Year Treetime limit per test3 secondsmemory limit per test256 megabytesinputstandard inputout ...

  2. codeforces 620E. New Year Tree dfs序+线段树+bitset

    题目链接 给一棵树, 每个节点有颜色, 两种操作, 一种是将一个节点的子树全都染色成c, 一种是查询一个节点的子树有多少个不同的颜色, c<=60. 每个节点一个bitset维护就可以. #in ...

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

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

  4. Codeforces Round #225 (Div. 2) E. Propagating tree dfs序+-线段树

    题目链接:点击传送 E. Propagating tree time limit per test 2 seconds memory limit per test 256 megabytes inpu ...

  5. Codeforces 916E Jamie and Tree (换根讨论)

    题目链接  Jamie and Tree 题意  给定一棵树,现在有下列操作: $1$.把当前的根换成$v$:$2$.找到最小的同时包含$u$和$v$的子树,然后把这棵子树里面的所有点的值加$x$: ...

  6. POJ3321 - Apple Tree DFS序 + 线段树或树状数组

    Apple Tree:http://poj.org/problem?id=3321 题意: 告诉你一棵树,每棵树开始每个点上都有一个苹果,有两种操作,一种是计算以x为根的树上有几个苹果,一种是转换x这 ...

  7. BZOJ - 2588 Spoj 10628. Count on a tree (可持久化线段树+LCA/树链剖分)

    题目链接 第一种方法,dfs序上建可持久化线段树,然后询问的时候把两点之间的所有树链扒出来做差. #include<bits/stdc++.h> using namespace std; ...

  8. CodeForces 916E Jamie and Tree(树链剖分+LCA)

    To your surprise, Jamie is the final boss! Ehehehe. Jamie has given you a tree with n vertices, numb ...

  9. Codeforces 916E(思维+dfs序+线段树+LCA)

    题面 传送门 题目大意:给定初始根节点为1的树,有3种操作 1.把根节点更换为r 2.将包含u,v的节点的最小子树(即lca(u,v)的子树)所有节点的值+x 3.查询v及其子树的值之和 分析 看到批 ...

随机推荐

  1. [Android]有关外部链接唤醒App需要注意的坑

    移动互联网发展到今天,一个移动app需要和各种各样的外部链接关联,它不再仅仅从手机的桌面启动,更多的将会从其他的应用.浏览器链接.短信.二维码或者微信分享等渠道启动,这里涉及到的是各种各样的营销渠道和 ...

  2. Struts2框架实现简单的用户登入

    Struts框架汲取了Struts的优点,以WebWork为核心,拦截器,可变和可重用的标签. 第一步:加载Struts2 类库: 第二步:配置web.xml <?xml version=&qu ...

  3. CNN结构:色彩特征提取-从RGB空间到HSV空间(色彩冷暖判断)

      转自知乎和百度百科:从零开始学后期             文章: 冷暖色区分?冷暖肤色适用于那些色系的彩妆?    文章:干货 |如何判断人体色冷暖?如何判断色彩冷暖?(值得收藏研读!) -蒜苗 ...

  4. 名词解释http隧道、https、SSL层、http代理、在线代理、socks代理区别

    以前听到这几个名词时,总是搞混淆,今天花点时间来记录这几个名词的大概区别,方便以后自己查看. http隧道与https http隧道:“HTTP隧道技术”就是把所有要传送的数据全部封装到HTTP协议里 ...

  5. BeginEditorCommand()

    BeginEditorCommand();开始把焦点给CAD CompleteEditorCommand();焦点给窗体

  6. 用C#在Visual Studio写Javascript单元测试

    1.在vs创建一个标准的单元测试工程 2.引用nuget包:Edge.js 我是用的是6.11.2版本 3.编写JsRunner类 using EdgeJs; using System; using ...

  7. centos vm 桥接 --网络配置

    /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0 BOOTPROTO=none BROADCAST=192.168.1.255 HWADDR= ...

  8. 使用Python的Flask框架,结合Highchart,动态渲染图表(Ajax 请求数据接口)

    参考链接:https://www.highcharts.com.cn/docs/ajax 参考链接中的示例代码是使用php写的,这里改用python写. 需要注意的地方: 1.接口返回的数据格式,这个 ...

  9. 解决Eclipse导入项目后Validating验证缓慢的问题

    减少不必要的验证即可 步骤:Window-Preferences-左侧的Validation 如图所示,将Build一列的勾全部去掉就好了. 如需手动校验,右键项目名-选择Validate即可.

  10. CF586D. Phillip and Trains

    /* CF586D. Phillip and Trains http://codeforces.com/problemset/problem/586/D 搜索 */ #include<cstdi ...