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. Visual Studio 2015 Test Explorer does not show anything

    Problem After install Visual Studio 2015 community and NUnit Test Adapter, I cannot find test cases ...

  2. uvaoj1585Score(暴力)

    1585 ScoreThere is an objective test result such as “OOXXOXXOOO”. An ‘O’ means a correct answer of a ...

  3. php随机类型验证码

    开发使用验证码的意义就是为了区别操作者是人还是机器,防止自动脚本对服务器造成灾难性的攻击 目前有各种各样的验证码种类,譬如:静态字符验证码.算术验证码.拖拽验证码.识别文字或识别物品验证码(高级),下 ...

  4. 概要梳理kafka知识点

    主要是梳理一下kafka学习中的一些注意点,按照消息的流动方向进行梳理.详细的kafka介绍推荐看骑着龙的羊的系列博客,具体的某一块的知识点,可以参考我给出的一些参考文章. 1. kafka在系统中的 ...

  5. 6.hdfs的存储过程

    1.hdfs 怎么存储 切割存储 2. 为何每块是128m 与io读写速度有关,一般人的接受速度1s中,而磁盘的读写速度为100m/s,在读取文件时候需要硬盘寻找地址,一般读懂速度和寻找之间的比例是1 ...

  6. C Program进阶-数组

    (一)数组的内存布局 对于语句int a[5]; 我们明白这里定义了一个数组,数组里有5个元素,每一个元素都是int类型,我们可以用a[0],a[1]等访问数组里的元素,但是这些元素的名字就是a[0] ...

  7. 第一次接触FPGA至今,总结的宝贵经验

    从大学时代第一次接触FPGA至今已有10多年的时间,至今记得当初第一次在EDA实验平台上完成数字秒表.抢答器.密码锁等实验时那个兴奋劲.当时由于没有接触到HDL硬件描述语言,设计都是在MAX+plus ...

  8. 如何理解*p++

    后置递增运算符的优先级高于解引用运算符! *p++ 等价于 *(p++) 但是,我们*p++的求值结果不可理解为p+1指向的对象的值,而应该是p指向的对象的值. 这是由于后置++的特性引起的. *p+ ...

  9. 自学系列--git的基础简介

    上学期第一次接触git,感觉挺难的,我们都知道这个非常重要,自己对git也自学了一段时间,下面这是对自学内容的总结,拿出来和大家一块交流一下,让我们一起成长吧! 一 git简介 Git是一个开源的分布 ...

  10. LintCode-366.斐波纳契数

    斐波纳契数列 查找斐波纳契数列中第 N 个数. 所谓的斐波纳契数列是指: 前2个数是 0 和 1 . 第 i 个数是第 i-1 个数和第i-2 个数的和. 斐波纳契数列的前10个数字是:0, 1, 1 ...