题面

解析

这题考试时刚了四个小时.

结果还是爆零了

主要就是因为\(lca\)找伪了.

我们先考虑没有操作1,那就是裸的线段树.

在换了根以后,主要就是\(lca\)不好找(分类讨论伪了).

我们将一开始以\(1\)为根的图作为原图.

仔细思考一下,

我们会发现只有当原图上的\(lca\)在\(1\)和当前的根的路径上时,\(lca\)才会发生变化.

考试时怎么没发现

而当\(lca\)变化后,我们画一下图,

就会发现,

现在的\(lca\)就是两个点与根的\(lca\)中深度较大的一个.

(这个\(yy\)一下就能明白了)

然后,我们再考虑修改\查询.(实际上它们的道理是一样的)

假设我们要修改\查询的是\(p\)的子树,

如果根不在\(p\)的子树里,就直接来就行了,

否则,从根到\(p\)的路径上的所有分出去的点就不会被修改(画下图就能明白),

所以我们直接全图加一下,

设根在\(p\)的儿子\(k\)的子树里,

那么将\(k\)的子树全部减一下就行了.

至于找\(k\),可以用倍增,

修改\查询可以用线段树&树链剖分.

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#define int long long
#define ls(a) a<<1
#define rs(a) a<<1|1
#define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout)
using namespace std; inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return f*sum;
} const int N=600001;
struct tree{int l,r,sum,tag;}t[N<<1];
struct node{int val,fa,size,son,dep,id,top;}a[N];
struct edge{int to,next;}e[N<<1];
int n,m,rt=1;
int head[N],cnt=0;
int tot,pla[N],f[N][21]; inline void add(int x,int y){
e[++cnt]=(edge){head[x],y};head[x]=cnt;
} void dfs1(int x,int fa){
a[x].size=1;a[x].fa=fa;a[x].dep=a[fa].dep+1;
f[x][0]=fa;
for(int i=1;i<=20;i++) f[x][i]=f[f[x][i-1]][i-1];
for(int i=head[x];i;i=e[i].to){
int k=e[i].next;if(k==fa) continue;
dfs1(k,x);a[x].size+=a[k].size;
if(!a[x].son||a[k].size>a[a[x].son].size) a[x].son=k;
}
} void dfs2(int x,int top){
a[x].top=top;a[x].id=++tot;pla[tot]=x;
if(a[x].son) dfs2(a[x].son,top);
for(int i=head[x];i;i=e[i].to){
int k=e[i].next;if(k==a[x].fa||k==a[x].son) continue;
dfs2(k,k);
}
} inline int lca(int x,int y){
while(a[x].top!=a[y].top){
if(a[a[x].top].dep<a[a[y].top].dep) swap(x,y);
x=a[a[x].top].fa;
}
if(a[x].dep>a[y].dep) swap(x,y);
return x;
} inline void pushup(int p){
t[p].sum=t[ls(p)].sum+t[rs(p)].sum;
} inline void pushdown(int p){
if(!t[p].tag) return ;
int l=ls(p),r=rs(p);
t[l].tag+=t[p].tag;t[r].tag+=t[p].tag;
t[l].sum+=(t[l].r-t[l].l+1)*t[p].tag;
t[r].sum+=(t[r].r-t[r].l+1)*t[p].tag;
t[p].tag=0;
} inline void sg_build(int p,int l,int r){
t[p].l=l;t[p].r=r;
if(l==r){t[p].sum=a[pla[l]].val;return ;}
int mid=(l+r)>>1;
sg_build(ls(p),l,mid);sg_build(rs(p),mid+1,r);
pushup(p);
} inline void sg_change(int p,int l,int r,int w){
if(t[p].l>=l&&t[p].r<=r){
t[p].sum+=(t[p].r-t[p].l+1)*w;t[p].tag+=w;
return ;
}
pushdown(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid) sg_change(ls(p),l,r,w);
if(r>mid) sg_change(rs(p),l,r,w);
pushup(p);
} inline int sg_query(int p,int l,int r){
if(t[p].l>=l&&t[p].r<=r) return t[p].sum;
pushdown(p);
int mid=(t[p].l+t[p].r)>>1,ret=0;
if(l<=mid) ret+=sg_query(ls(p),l,r);
if(r>mid) ret+=sg_query(rs(p),l,r);
pushup(p);
return ret;
} inline int isson(int x,int fa){return a[x].id>=a[fa].id&&a[x].id<=a[fa].id+a[fa].size-1;} inline void change(int x,int y,int w){
int p=lca(x,y);
int f1=lca(p,rt);
if(f1==p){
f1=lca(x,rt);int f2=lca(y,rt);
if(a[f1].dep>a[f2].dep) p=f1;
else p=f2;
}
if(!isson(rt,p)) sg_change(1,a[p].id,a[p].id+a[p].size-1,w);
else{
sg_change(1,1,n,w);int k=rt;
if(isson(k,p)&&rt!=p){
for(int i=20;i>=0;i--)
if(a[f[k][i]].dep>a[p].dep) k=f[k][i];
sg_change(1,a[k].id,a[k].id+a[k].size-1,-w);
}
}
} inline void ask(int p){
int ret=0;
if(a[rt].id>a[p].id+a[p].size-1||a[rt].id<a[p].id) ret=sg_query(1,a[p].id,a[p].id+a[p].size-1);
else{
ret+=sg_query(1,1,n);int k=rt;
if(isson(k,p)&&rt!=p){
for(int i=20;i>=0;i--)
if(a[f[k][i]].dep>a[p].dep) k=f[k][i];
ret-=sg_query(1,a[k].id,a[k].id+a[k].size-1);
}
}
printf("%lld\n",ret);
} signed main(){
n=read();m=read();
for(int i=1;i<=n;i++) a[i].val=read();
for(int i=1;i<n;i++){int x=read(),y=read();add(x,y);add(y,x);}
dfs1(1,0);dfs2(1,1);sg_build(1,1,n);
for(int i=1;i<=m;i++){
int opt=read(),x=read();
if(opt==1) rt=x;
else if(opt==2) {int y=read(),w=read();change(x,y,w);}
else if(opt==3) ask(x);
}
return 0;
}
/*
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
*/

题解 [CF916E] Jamie and Tree的更多相关文章

  1. CF916E Jamie and Tree

    CF916E Jamie and Tree 题意翻译 有一棵n个节点的有根树,标号为1-n,你需要维护以下三种操作 1.给定一个点v,将整颗树的根变为v 2.给定两个点u, v,将lca(u, v)所 ...

  2. CF916E Jamie and Tree 解题报告

    CF916E Jamie and Tree 题意翻译 有一棵\(n\)个节点的有根树,标号为\(1-n\),你需要维护一下三种操作 1.给定一个点\(v\),将整颗树的根变为\(v\) 2.给定两个点 ...

  3. 【树剖】CF916E Jamie and Tree

    好吧这其实应该不是树剖... 因为只要求子树就够了,dfs就好了 大概就是记录一个全局根root 多画几幅图会发现修改时x,y以root为根时的lca为以1为根时的lca(x,y),lca(root, ...

  4. codeforces 916E Jamie and Tree dfs序列化+线段树+LCA

    E. Jamie and Tree time limit per test 2.5 seconds memory limit per test 256 megabytes input standard ...

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

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

  6. 题解:CF593D Happy Tree Party

    题解:CF593D Happy Tree Party Description Bogdan has a birthday today and mom gave him a tree consistin ...

  7. 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 ...

  8. 题解-CF429C Guess the Tree

    题面 CF429C Guess the Tree 给一个长度为 \(n\) 的数组 \(a_i\),问是否有一棵树,每个节点要么是叶子要么至少有两个儿子,而且 \(i\) 号点的子树大小是 \(a_i ...

  9. 题解-AtCoder Code-Festival2017 Final-J Tree MST

    Problem \(\mathrm{Code~Festival~2017~Final~J}\) 题意概要:一棵 \(n\) 个节点有点权边权的树.构建一张完全图,对于任意一对点 \((x,y)\),连 ...

随机推荐

  1. oracle杀死正在执行的进程

    1 查询目前正在执行的终端和进程, SELECT /*+ rule */ s.username,decode(l.type,'TM','TABLE LOCK','TX','ROW LOCK',NULL ...

  2. spark 执行报错 java.io.EOFException: Premature EOF from inputStream

    使用spark2.4跟spark2.3 做替代公司现有的hive选项. 跑个别任务spark有以下错误 java.io.EOFException: Premature EOF from inputSt ...

  3. c# dateTime格式转换为Unix时间戳工具类

    using System; using System.Collections.Generic; using System.Text; namespace TJCFinanceWriteOff.BizL ...

  4. Kubernetes组件-ReplicaSet

    ⒈简介 最初,ReplicationController是Kubernetes用于复制和在异常时重新调度节点的唯一组件,后来Kubernetes又引入了一个名为ReplicaSet的类似资源.它是新一 ...

  5. Pygame小游戏练习二

    @Python编程从入门到实践 Python项目练习 四.创建Ship类 建立ship.py,创建Ship类,管理飞船行为. # ship.py import pygame class Ship(): ...

  6. 移动端测试之APP安全测试

    现在APP测试已经是测试行业的一个重要分支,对APP测试技能和经验的要求也越来越高,看到一篇关于APP安全测试的总结,分享给需要的朋友.1.软件权限1)扣费风险:包括发送短信.拨打电话.连接网络等2) ...

  7. 简单分析BeanPostProcessor

    1. 什么是BeanPostProcessorBeanPostProcessor是一个接口,有两个方法,分别是:Object postProcessBeforeInitialization(Objec ...

  8. 复习二叉数 pat l2-006 数的遍历

    L2-006. 树的遍历   给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列.这里假设键值都是互不相等的正整数. 输入格式: 输入第一行给出一个正整数N(<=30),是二叉树中结点 ...

  9. C#通讯框架改写

    现有项目是利用C#的socket与PLC进行实时通讯,PLC有两种通讯模式——常规采集&高频采集. 其中常规采集大概在10ms左右发送一次数据,高频采集大概在2ms左右发送一次数据. 现有代码 ...

  10. jquery.serializejson.min.js的妙用

    关于这个jquery.serializejson.min.js插件来看,他是转json的一个非常简单好用的插件. 前端在处理含有大量数据提交的表单时,除了使用Form直接提交刷新页面之外,经常碰到的需 ...