题面

解析

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

结果还是爆零了

主要就是因为\(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. [转帖]Mysql binlog 介绍

    binlog介绍   1.什么是binlog binlog是一个二进制格式的文件,用于记录用户对数据库更新的SQL语句信息,例如更改数据库表和更改内容的SQL语句都会记录到binlog里,但是对库表等 ...

  2. leetCode算法——1TwoSum(两数之和)

    描述: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中 ...

  3. J.U.C之AQS介绍

    从JDK1.5开始,引入了并发包java.util.concurrent(J.U.C),并发容器里的同步容器AQS(AbstractQueuedSynchronizer)是J.U.C的核心,AQS底层 ...

  4. Timezone offset does not match system offset: 0 != -32400. Please, check your config files

    apscheduler使用uWSGI的mule模块部署的时候报错, 因为系统时区和代码运行时区不一样导致. 解决办法:在初始化的时候指定上海的时区 scheduler = BlockingSchedu ...

  5. MGR+Consul集群

    [root@mydb1 ~]# wget https://releases.hashicorp.com/consul/1.4.0/consul_1.4.0_linux_amd64.zip[root@m ...

  6. 【原创】大叔经验分享(80)openresty(nginx+lua)发邮件

    nginx配置 lua_package_path "/usr/local/openresty/lualib/resty/smtp/?.lua;;"; lua_need_reques ...

  7. c++11 用户定义字面量

    c++11 用户定义字面量 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #inc ...

  8. vue学习(9)-路由守卫

    全局守卫 你可以使用 router.beforeEach 注册一个全局前置守卫: const router = new VueRouter({ ... })   router.beforeEach(( ...

  9. 不显示Zetero导出的文献库中的部分内容

    不显示Zetero导出的文献库中的部分内容 Zetero作为文献管理软件,收集到的参考文献的相关信息(域fields)比较齐全.文章或书籍的引用中仅仅只用到了其中的一部分,如作者.发表年.题名.期刊( ...

  10. echo打印换行

    shell环境中,echo是常用的数据命令,但有的时候,想通过“\n”使输出换行却换不了,这个时候需要增加-e选项: $ echo "Hellow.\nHey man~" Hell ...