题解 [CF916E] Jamie and Tree
解析
这题考试时刚了四个小时.
结果还是爆零了
主要就是因为\(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的更多相关文章
- CF916E Jamie and Tree
CF916E Jamie and Tree 题意翻译 有一棵n个节点的有根树,标号为1-n,你需要维护以下三种操作 1.给定一个点v,将整颗树的根变为v 2.给定两个点u, v,将lca(u, v)所 ...
- CF916E Jamie and Tree 解题报告
CF916E Jamie and Tree 题意翻译 有一棵\(n\)个节点的有根树,标号为\(1-n\),你需要维护一下三种操作 1.给定一个点\(v\),将整颗树的根变为\(v\) 2.给定两个点 ...
- 【树剖】CF916E Jamie and Tree
好吧这其实应该不是树剖... 因为只要求子树就够了,dfs就好了 大概就是记录一个全局根root 多画几幅图会发现修改时x,y以root为根时的lca为以1为根时的lca(x,y),lca(root, ...
- 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 ...
- Codeforces 916E Jamie and Tree (换根讨论)
题目链接 Jamie and Tree 题意 给定一棵树,现在有下列操作: $1$.把当前的根换成$v$:$2$.找到最小的同时包含$u$和$v$的子树,然后把这棵子树里面的所有点的值加$x$: ...
- 题解:CF593D Happy Tree Party
题解:CF593D Happy Tree Party Description Bogdan has a birthday today and mom gave him a tree consistin ...
- 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 ...
- 题解-CF429C Guess the Tree
题面 CF429C Guess the Tree 给一个长度为 \(n\) 的数组 \(a_i\),问是否有一棵树,每个节点要么是叶子要么至少有两个儿子,而且 \(i\) 号点的子树大小是 \(a_i ...
- 题解-AtCoder Code-Festival2017 Final-J Tree MST
Problem \(\mathrm{Code~Festival~2017~Final~J}\) 题意概要:一棵 \(n\) 个节点有点权边权的树.构建一张完全图,对于任意一对点 \((x,y)\),连 ...
随机推荐
- No package 'eventlog' found
syslog-ng のインスト�ル手� ●ダウンロ�ドサイト http://www.balabit.com/downloads/files/syslog-ng/sources/stable/src/ ...
- 把Javascript 对象转换为键值对连接符字符串的方法总结
307down votefavorite 93 Do you know a fast and simple way to encode a Javascript Object into a strin ...
- 浅谈 JDBC 中 CreateStatement 和 PrepareStatement 的区别与优劣
先说下这俩到底是干啥的吧.其实这俩干的活儿都一样,就是创建了一个对象然后去通过对象调用executeQuery方法来执行sql语句.说是CreateStatement和PrepareStatement ...
- 【Python基础】13_Python中的PASS
pass关键字的使用 在程序分支中,如果不想立刻执行该分支,可使用pass占位符,pass不表示任何含义,仅保证程序不会报错. 如: action_str = input("请选择希望执行的 ...
- spark异常篇-Removing executor 5 with no recent heartbeats: 120504 ms exceeds timeout 120000 ms 可能的解决方案
问题描述与分析 题目中的问题大致可以描述为: 由于某个 Executor 没有按时向 Driver 发送心跳,而被 Driver 判断该 Executor 已挂掉,此时 Driver 要把 该 Exe ...
- Kali Linux安装AWVS漏扫工具
Acunetix是全球排名前三的漏洞发现厂商,其全称(Acunetix Web Vulnerability Scanner)AWVS是业内领先的网络漏洞扫描器,其被广泛赞誉为包括最先进的SQL注入和X ...
- ubuntu+nginx+uwsgi部署django web项目
前言 将本地开发的django项目部署至linux上的uwsgi服务器,并配置nginx,完成基于ubuntu+nginx+uwsgi的上线运行.下面整理相关步骤. 服务器配置virtualenv 如 ...
- 核发电站 (dp前缀优化)
大意: $n$个城市, $m$种核电站, 第$i$种假设要建在第$x$个城市, 必须满足$[x-i,x+i]$范围内无其他核电站, 求建核电站的方案数. 简单$dp$题, 设$dp[i][j]$为位置 ...
- c#将电脑时间同步到网络时间
最近遇到个项目,需要控制软件使用时间,由于电脑不联网可以修改时间,故需要联网使电脑同步网络时间 网上寻找了很多解决方案,代码如下: //Forproc_Win32.cs//对常用Win32 API函数 ...
- C# 委托 、事件、同步、异步知识点归纳
一.委托 基本用法: 1.声明一个委托类型.委托就像是‘类'一样,声明了一种委托之后就可以创建多个具有此种特征的委托.(特征,指的是返回值.参数类型) public delegate void Som ...