题面

解析

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

结果还是爆零了

主要就是因为\(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. No package 'eventlog' found

    syslog-ng のインスト�ル手� ●ダウンロ�ドサイト http://www.balabit.com/downloads/files/syslog-ng/sources/stable/src/ ...

  2. 把Javascript 对象转换为键值对连接符字符串的方法总结

    307down votefavorite 93 Do you know a fast and simple way to encode a Javascript Object into a strin ...

  3. 浅谈 JDBC 中 CreateStatement 和 PrepareStatement 的区别与优劣

    先说下这俩到底是干啥的吧.其实这俩干的活儿都一样,就是创建了一个对象然后去通过对象调用executeQuery方法来执行sql语句.说是CreateStatement和PrepareStatement ...

  4. 【Python基础】13_Python中的PASS

    pass关键字的使用 在程序分支中,如果不想立刻执行该分支,可使用pass占位符,pass不表示任何含义,仅保证程序不会报错. 如: action_str = input("请选择希望执行的 ...

  5. spark异常篇-Removing executor 5 with no recent heartbeats: 120504 ms exceeds timeout 120000 ms 可能的解决方案

    问题描述与分析 题目中的问题大致可以描述为: 由于某个 Executor 没有按时向 Driver 发送心跳,而被 Driver 判断该 Executor 已挂掉,此时 Driver 要把 该 Exe ...

  6. Kali Linux安装AWVS漏扫工具

    Acunetix是全球排名前三的漏洞发现厂商,其全称(Acunetix Web Vulnerability Scanner)AWVS是业内领先的网络漏洞扫描器,其被广泛赞誉为包括最先进的SQL注入和X ...

  7. ubuntu+nginx+uwsgi部署django web项目

    前言 将本地开发的django项目部署至linux上的uwsgi服务器,并配置nginx,完成基于ubuntu+nginx+uwsgi的上线运行.下面整理相关步骤. 服务器配置virtualenv 如 ...

  8. 核发电站 (dp前缀优化)

    大意: $n$个城市, $m$种核电站, 第$i$种假设要建在第$x$个城市, 必须满足$[x-i,x+i]$范围内无其他核电站, 求建核电站的方案数. 简单$dp$题, 设$dp[i][j]$为位置 ...

  9. c#将电脑时间同步到网络时间

    最近遇到个项目,需要控制软件使用时间,由于电脑不联网可以修改时间,故需要联网使电脑同步网络时间 网上寻找了很多解决方案,代码如下: //Forproc_Win32.cs//对常用Win32 API函数 ...

  10. C# 委托 、事件、同步、异步知识点归纳

    一.委托 基本用法: 1.声明一个委托类型.委托就像是‘类'一样,声明了一种委托之后就可以创建多个具有此种特征的委托.(特征,指的是返回值.参数类型) public delegate void Som ...