题面

解析

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

结果还是爆零了

主要就是因为\(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. SpringBoot 使用WebSocket打造在线聊天室

    教程: https://www.jianshu.com/p/55cfc9fcb69e https://wallimn.iteye.com/blog/2425666 关于websocket基础普及见:h ...

  2. HashMap集合-遍历方法

    # HashMap集合-遍历方法 先定义好集合: public static void main(String[] args) { Map<String,String> onemap=ne ...

  3. idea启动tomcat时报错:Error during artifact deployment. See server log for details.

    Error during artifact deployment. See server log for details. 这个很多人都找不出来,原因无非2个: 一.jar 包有有些没能识别,tomc ...

  4. git太慢用码云

    克隆完之后,我们要对这个仓库进行下修改,将仓库地址修改为git的那个 git remote set-url origin xxxx.git 经过以上操作,这个仓库就和从github上克隆下来的一模一样

  5. HTNL基础之四

    11.<nav>导航元素 标签定义及使用说明 表示页面中导航链接的部分,例如:传统导航条,侧边栏导航,页内导航,翻页等 <nav> 标签定义导航链接的部分. 并不是所有的 HT ...

  6. Scrapy爬虫-win7下创建运行项目

    开始的时候,我只安装了python3.5,安装不了scrapy库,网上搜了一下说是scrapy不支持python3.x 然后,我就又安装了python2.7 为了,默认使用2.7,我在环境变量path ...

  7. 基于白名单的Payload

    利用 Msiexec 命令DLL反弹 Msiexec是Windows Installer的一部分.用于安装Windows Installer安装包(MSI),一般在运行Microsoft Update ...

  8. DeepMind提出新型超参数最优化方法:性能超越手动调参和贝叶斯优化

    DeepMind提出新型超参数最优化方法:性能超越手动调参和贝叶斯优化 2017年11月29日 06:40:37 机器之心V 阅读数 2183   版权声明:本文为博主原创文章,遵循CC 4.0 BY ...

  9. Java面试题之Java虚拟机垃圾回收

    JVM的垃圾回收机制,在内存充足的情况下,除非你显式的调用System.gc(),否则不会进行垃圾回收:在内存充足的情况下垃圾回收会自动运行. 一.引用计数算法 1.定义:引用计数算法会给对象添加一个 ...

  10. HashMap闭环(死循环)的详细原因(转)

    为何出现死循环简要说明 HashMap是非线程安全的,在并发场景中如果不保持足够的同步,就有可能在执行HashMap.get时进入死循环,将CPU的消耗到100%. HashMap采用链表解决Hash ...