CF916E Jamie and Tree

题意翻译

有一棵\(n\)个节点的有根树,标号为\(1-n\),你需要维护一下三种操作

1.给定一个点\(v\),将整颗树的根变为\(v\)

2.给定两个点\(u, v\),将\(lca(u, v)\)所在的子树都加上\(x\)

3.给定一个点\(v\),你需要回答以\(v\)所在的子树的权值和

输入输出格式

输入格式:

The first line of input contains two space-separated integers \(n\) and \(q\) \((1<=n<=10^{5},1<=q<=10^{5})\) — the number of vertices in the tree and the number of queries to process respectively.

The second line contains \(n\) space-separated integers\(a_{1},a_{2},...,a_{n}\)(\(-10^{8}<=a_{i}<=10^{8}\)) — initial values of the vertices.

Next \(n-1\) lines contains two space-separated integers\(u_{i},v_{i}\)(\(1<=u_{i},v_{i}<=n\)) describing edge between vertices \(u_{i}\)and \(v_{i}\)in the tree.

The following \(q\) lines describe the queries.

Each query has one of following formats depending on its type:

\(1\ v\) ( \(1<=v<=n\) ) for queries of the first type.

\(2\ u\ v\ x\) ( \(1<=u,v<=n,-10^{8}<=x<=10^{8}\) ) for queries of the second type.

\(3\ v ( 1<=v<=n )\) for queries of the third type.

All numbers in queries' descriptions are integers.

The queries must be carried out in the given order. It is guaranteed that the tree is valid.

输出格式:

For each query of the third type, output the required answer. It is guaranteed that at least one query of the third type is given by Jamie.


强制换根==分类讨论

如果在考场上比较难写就考虑暴力吧

首先介绍几点可能比较常见的

1.换根后的\(lca(u,v)\)

其实求法比较多,介绍一种

设\(z1=lca(u,root),z2=lca(v,root)\),如果\(z1==z2\),则\(lca(u,v)\)不变,否则\(lca(u,v)\)为\(z1,z2\)中深度较深的那个

2.一个点是否在某点的子树里

bool in(int x)
{
if(dfn[x]>=dfn[root]&&dfn[x]<=dfn[root]+siz[root]-1) return true;
return false;
}

对于这道题,我们在分类讨论上稍稍用一点容斥原理即可


Code:

#include <cstdio>
#define ll long long
#define ls id<<1
#define rs id<<1|1
const int N=100010;
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
to[++cnt]=v;Next[cnt]=head[u];head[u]=cnt;
}
int f[N][20],dfn[N],dep[N],siz[N],ha[N],dfs_clock,root;
void dfs(int now)
{
dfn[now]=++dfs_clock;
ha[dfs_clock]=now;
siz[now]++;
for(int i=head[now];i;i=Next[i])
{
int v=to[i];
if(f[now][0]!=v)
{
dep[v]=dep[now]+1;
f[v][0]=now;
dfs(v);
siz[now]+=siz[v];
}
}
}
ll sum[N<<2],lazy[N<<2],dat[N];
int n,q;
void updata(int id)
{
sum[id]=sum[ls]+sum[rs];
}
void push_down(int id,ll L,ll R)
{
if(!lazy[id]) return;
if(L!=R)
{
ll mid=L+R>>1;
sum[ls]+=(mid+1-L)*lazy[id];
sum[rs]+=(R-mid)*lazy[id];
lazy[ls]+=lazy[id];
lazy[rs]+=lazy[id];
}
lazy[id]=0;
}
void build(int id,int l,int r)
{
if(l==r)
{
sum[id]=dat[ha[l]];
return;
}
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
updata(id);
}
void change(int id,ll l,ll r,ll L,ll R,ll delta)
{
push_down(id,L,R);
if(l==L&&r==R)
{
sum[id]+=(R+1-L)*delta;
lazy[id]+=delta;
return;
}
ll mid=L+R>>1;
if(r<=mid) change(ls,l,r,L,mid,delta);
else if(l>mid) change(rs,l,r,mid+1,R,delta);
else change(ls,l,mid,L,mid,delta),change(rs,mid+1,r,mid+1,R,delta);
updata(id);
}
ll query(int id,ll l,ll r,ll L,ll R)
{
push_down(id,L,R);
if(l==L&&r==R) return sum[id];
ll mid=L+R>>1;
if(r<=mid) return query(ls,l,r,L,mid);
else if(l>mid) return query(rs,l,r,mid+1,R);
else return query(ls,l,mid,L,mid)+query(rs,mid+1,r,mid+1,R);
}
void init()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%lld",dat+i);
for(int u,v,i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dep[1]=1;
dfs(root=1);
for(int j=1;j<=18;j++)
for(int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
build(1,1,n);
}
void Swap(int &x,int &y)
{
int tmp=x;
x=y;
y=tmp;
}
int LCA0(int x,int y)//原树的LCA
{
if(dep[x]<dep[y]) Swap(x,y);
for(int i=18;~i;i--)
if(dep[f[x][i]]>=dep[y])
x=f[x][i];
if(x==y) return x;
for(int i=18;~i;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int LCA(int x,int y)//换根后的LCA
{
int z1=LCA0(x,root),z2=LCA0(y,root);
if(z1==z2) return LCA0(x,y);
else return dep[z1]>dep[z2]?z1:z2;
}
bool in(int x)//询问x是否在以root为根的子树里
{
if(dfn[x]>=dfn[root]&&dfn[x]<=dfn[root]+siz[root]-1) return true;
return false;
}
int querys(int x)//询问根到x位置上x的那个儿子
{
int y=root;
for(int i=18;~i;i--)
if(dep[f[y][i]]>dep[x])
y=f[y][i];
return y;
}
void modify(int x,ll delta)//给以x为根的子树加上delta
{
if(in(x))
{
if(x!=root) change(1,dfn[x],dfn[x]+siz[x]-1,1,n,delta);
else change(1,1,n,1,n,delta);
return;
}
int son=querys(x);
if(f[son][0]==x)
{
change(1,1,n,1,n,delta);
change(1,dfn[son],dfn[son]+siz[son]-1,1,n,-delta);
}
else
change(1,dfn[x],dfn[x]+siz[x]-1,1,n,delta);
}
ll ask(int x)//询问新根下子树权值和
{
if(in(x))
{
if(x!=root) return query(1,dfn[x],dfn[x]+siz[x]-1,1,n);
return query(1,1,n,1,n);
}
int son=querys(x);
ll ans=0;
if(f[son][0]==x)
{
ans+=query(1,1,n,1,n);
ans-=query(1,dfn[son],dfn[son]+siz[son]-1,1,n);
}
else
ans=query(1,dfn[x],dfn[x]+siz[x]-1,1,n);
return ans;
}
void work()
{
ll x;
for(int opt,u,v,i=1;i<=q;i++)
{
scanf("%d",&opt);
if(opt==1)
{
scanf("%d",&u);
root=u;
}
else if(opt==2)
{
scanf("%d%d%lld",&u,&v,&x);
modify(LCA(u,v),x);
}
else
{
scanf("%d",&u);
printf("%lld\n",ask(u));
}
}
}
int main()
{
init();
work();
return 0;
}

2018.7.31

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. 【LeetCode】863. All Nodes Distance K in Binary Tree 解题报告(Python)

    [LeetCode]863. All Nodes Distance K in Binary Tree 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http ...

  3. 【LeetCode】297. Serialize and Deserialize Binary Tree 解题报告(Python)

    [LeetCode]297. Serialize and Deserialize Binary Tree 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode ...

  4. 【LeetCode】331. Verify Preorder Serialization of a Binary Tree 解题报告(Python)

    [LeetCode]331. Verify Preorder Serialization of a Binary Tree 解题报告(Python) 标签: LeetCode 题目地址:https:/ ...

  5. 【LeetCode】109. Convert Sorted List to Binary Search Tree 解题报告(Python)

    [LeetCode]109. Convert Sorted List to Binary Search Tree 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id ...

  6. 【LeetCode】236. Lowest Common Ancestor of a Binary Tree 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  7. 【LeetCode】99. Recover Binary Search Tree 解题报告(Python)

    [LeetCode]99. Recover Binary Search Tree 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/p ...

  8. 【LeetCode】662. Maximum Width of Binary Tree 解题报告(Python)

    [LeetCode]662. Maximum Width of Binary Tree 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://leetcode.co ...

  9. 【LeetCode】623. Add One Row to Tree 解题报告(Python)

    [LeetCode]623. Add One Row to Tree 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/problem ...

随机推荐

  1. mysql 开启远程连接

    如图,修改mysql数据库中user表中的User字段为root的host为%,然后重新启动mysql服务即可让远程桌面连接本地.

  2. mysql优化理解笔记(持续更新)

    主要包括存储引擎.索引.sql语句 一.存储引擎 目前最常见的是InnoDB和MyISAM两个存储引擎 (1)InnoDB:支持事务处理,提供行级锁.外键约束索引,行锁 (2)MyISAM:支持全文搜 ...

  3. Linux命令应用大词典-第16章 归档和压缩

    16.1 tar:进行归档和压缩 16.2 gzip:压缩或解压缩gzip文件 16.3 gunzip:解压缩gzip文件 16.4 zcmp:比较gzip压缩文件 16.5 zdiff:比较gzip ...

  4. python学习笔记03 --------------程序交互与格式化输出

    1.读取用户输入内容 语法:input() 例: name = input('你的名字是?) print('你好'+name) 程序会等待用户输入名字后打印:你好(用户输入的名字) 注意:input接 ...

  5. 一种跨平台的C++遍历目录的方法

    参考了网络上各路大神的实现方法.主要使用了io.h库 #include <iostream> #include <cstring> #include <io.h> ...

  6. day21 TFRecord格式转换MNIST并显示

    首先简要介绍了下TFRecord格式以及内部实现protobuf协议,然后基于TFRecord格式,对MNIST数据集转换成TFRecord格式,写入本地磁盘文件,再从磁盘文件读取,通过pyplot模 ...

  7. SGU 326 Perspective(最大流)

    Description Breaking news! A Russian billionaire has bought a yet undisclosed NBA team. He's plannin ...

  8. 给你的WP应用加上帮助文档

    背景 这算是Windows Phone编程回顾续篇, 接着给大家聊WP开发经验. 在开发了数个WP应用并发布后, 陆续收到很多反馈邮件, 其中接近一半的邮件是在问"某某功能有没有?" ...

  9. Android开发技巧--Application, ListView排列,格式化浮点数,string.xml占位符,动态引用图片

    一. Application用途 1. Application用途 创建Application时机 : Application在启动的时候会调用Application无参的构造方法创建实例; Appl ...

  10. [转]Windows 7 蓝屏后获取 MEMORY.DMP 文件及注意事项

    转自:http://hi.baidu.com/guicomeon/item/d6753a177fc76f0f8fbde46a 系统默认会在 C:\Windows 目录下创建 MEMORY.DMP 文件 ...