codeforces 916E Jamie and Tree dfs序列化+线段树+LCA
2.5 seconds
256 megabytes
standard input
standard output
To your surprise, Jamie is the final boss! Ehehehe.
Jamie has given you a tree with n vertices, numbered from 1 to n. Initially, the root of the tree is the vertex with number 1. Also, each vertex has a value on it.
Jamie also gives you three types of queries on the tree:
1 v — Change the tree's root to vertex with number v.
2 u v x — For each vertex in the subtree of smallest size that contains u and v, add x to its value.
3 v — Find sum of values of vertices in the subtree of vertex with number v.
A subtree of vertex v is a set of vertices such that v lies on shortest path from this vertex to root of the tree. Pay attention that subtree of a vertex can change after changing the tree's root.
Show your strength in programming to Jamie by performing the queries accurately!
The first line of input contains two space-separated integers n and q (1 ≤ n ≤ 105, 1 ≤ q ≤ 105) — the number of vertices in the tree and the number of queries to process respectively.
The second line contains n space-separated integers a1, a2, ..., an ( - 108 ≤ ai ≤ 108) — initial values of the vertices.
Next n - 1 lines contains two space-separated integers ui, vi (1 ≤ ui, vi ≤ n) describing edge between vertices ui and vi 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, - 108 ≤ x ≤ 108) 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.
- 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
- 27
19
5
- 4 6
4 3 5 6
1 2
2 3
3 4
3 1
1 3
2 2 4 3
1 1
2 2 4 -3
3 1
- 18
21
The following picture shows how the tree varies after the queries in the first sample.
大意:给出一颗树,初始根节点为1,三种操作:
1.把一个节点变成根节点
2.给出两个节点u,v,把包含这两个点的最小子树中每个节点权值加上x
3.查询以 u 为根的子树的权值和。
题解:
如果没有操作一,这题就是把LCA和dfs序列化以及线段树的板子放在一起。
但是,对于操作一,如何解决?
其实并不需要真的把节点提到根上。
我们可以一直以 1 为根节点,利用一些小结论来进行2和3操作。
假设在该图中,当前根节点为6,但是我们的dfs序列仍然是以1为根节点的。
如果当前根节点不在要修改(查询)的子树中,就没有任何影响,直接修改(查询)即可,此处不做讨论。
下面只说根节点在要修改(查询)的子树中的情况。
如果现在给出操作2,把包含2,4的最小子树上面的每个节点加delta。
我们应该处理的节点是 1 2 3 4 5
lca(2,4)=1 lca(2,6)=1 lca(4,6)=3
有一个大胆的猜想:
直接修改lca(2,4)=1的子树,然后把不该修改的哪部分改回去。
那么多修改的哪部分是那些呢:
大胆猜想:
取这三组lca中深度最大的那个(节点3)
当前的根节点6所在的 节点3的子树 就是多修改的那部分。
对于询问操作,思想大体相似
若当前根节点为6,询问1的子树的权值和。
先算上整颗树,然后减去多加的部分。
多加的部分就是根节点6所在的 节点1的子树,也就是3,4,5,6。
大胆猜想,不用证明,恩,这结论就是对的。
- /*
- Welcome Hacking
- Wish You High Rating
- */
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<ctime>
- #include<cstdlib>
- #include<algorithm>
- #include<cmath>
- #include<string>
- using namespace std;
- int read(){
- int xx=,ff=;char ch=getchar();
- while(ch>''||ch<''){if(ch=='-')ff=-;ch=getchar();}
- while(ch>=''&&ch<=''){xx=(xx<<)+(xx<<)+ch-'';ch=getchar();}
- return xx*ff;
- }
- const int maxn=;
- int N,Q,opt,t1,t2,t3,root,v[maxn];
- int tid[maxn],rk[maxn],tim,Prev[maxn],depth[maxn],end[maxn];
- int lin[maxn],len;
- struct edge{
- int y,next;
- }e[maxn<<];
- inline void insert(int xx,int yy){
- e[++len].next=lin[xx];
- lin[xx]=len;
- e[len].y=yy;
- }
- void dfs(int x,int prev){
- depth[x]=depth[prev]+;
- tid[x]=++tim;
- rk[tim]=x;
- Prev[x]=prev;
- for(int i=lin[x];i;i=e[i].next)
- if(e[i].y!=prev)
- dfs(e[i].y,x);
- end[x]=tim;
- }
- int f[][maxn];
- int LCA(int x,int y){
- if(depth[x]<depth[y])
- swap(x,y);
- int dif=depth[x]-depth[y];
- for(int i=;i>=;i--)
- if(dif&(<<i))
- x=f[i][x];
- if(x==y)
- return x;
- for(int i=;i>=;i--)
- if(f[i][x]!=f[i][y])
- x=f[i][x],y=f[i][y];
- return f[][x];
- }
- int LCALCA(int x,int y){
- int t1=LCA(x,y),t2=LCA(x,root),t3=LCA(y,root);
- if(depth[t1]<depth[t2])
- swap(t1,t2);
- if(depth[t1]<depth[t3])
- return t3;
- return t1;
- }
- int get_son(int x){
- int temp=root;
- int dif=depth[root]-depth[x]-;
- for(int i=;i>=;i--)
- if(dif&(<<i))
- temp=f[i][temp];
- return temp;
- }
- struct Segment_Tree{
- long long sum,tag;
- }T[maxn<<];
- int X,Y,Z;
- void build(int L,int R,int root){
- if(L==R){
- T[root].sum=v[rk[L]];
- return;
- }
- int mid=(L+R)>>;
- build(L,mid,root<<);
- build(mid+,R,root<<|);
- T[root].sum=T[root<<].sum+T[root<<|].sum;
- }
- void upd(int L,int R,int root){
- if(X>R||Y<L)
- return;
- if(X<=L&&Y>=R){
- T[root].tag+=Z;
- T[root].sum+=1LL*(R-L+)*Z;
- return;
- }
- int mid=(L+R)>>;
- if(T[root].tag){
- T[root<<].tag+=T[root].tag;
- T[root<<|].tag+=T[root].tag;
- T[root<<].sum+=T[root].tag*(mid-L+);
- T[root<<|].sum+=T[root].tag*(R-mid);
- T[root].tag=;
- }
- upd(L,mid,root<<);
- upd(mid+,R,root<<|);
- T[root].sum=T[root<<].sum+T[root<<|].sum;
- }
- long long query(int L,int R,int root){
- if(X>R||Y<L)
- return ;
- if(X<=L&&Y>=R)
- return T[root].sum;
- int mid=(L+R)>>;
- if(T[root].tag){
- T[root<<].tag+=T[root].tag;
- T[root<<|].tag+=T[root].tag;
- T[root<<].sum+=T[root].tag*(mid-L+);
- T[root<<|].sum+=T[root].tag*(R-mid);
- T[root].tag=;
- }
- return query(L,mid,root<<)+query(mid+,R,root<<|);
- }
- int main(){
- //freopen("in.txt","r",stdin);
- N=read(),Q=read();root=;
- for(int i=;i<=N;i++)
- v[i]=read();
- for(int i=;i<N;i++){
- t1=read(),t2=read();
- insert(t1,t2);
- insert(t2,t1);
- }
- dfs(,);
- /*for(int i=1;i<=N;i++)
- printf("%d ",tid[i]);
- puts("");
- for(int i=1;i<=N;i++)
- printf("%d ",rk[i]);
- puts("");
- for(int i=1;i<=N;i++)
- printf("%d ",depth[i]);
- puts("");*/
- build(,N,);
- for(int i=;i<=N;i++)
- f[][i]=Prev[i];
- for(int i=;i<=;i++)
- for(int j=;j<=N;j++)
- f[i][j]=f[i-][f[i-][j]];
- while(Q--){
- opt=read();
- if(opt==)
- root=read();
- else if(opt==){
- t1=read(),t2=read(),t3=read();
- int lca=LCALCA(t1,t2);
- if(tid[root]>=tid[lca]&&tid[root]<=end[lca]){
- X=,Y=N,Z=t3;
- upd(,N,);
- if(lca==root)
- continue;
- int temp=get_son(lca);
- X=tid[temp],Y=end[temp],Z=-t3;
- upd(,N,);
- }
- else{
- X=tid[lca],Y=end[lca],Z=t3;
- upd(,N,);
- }
- }
- else{
- int lca=read();
- if(lca==root){
- X=,Y=N;
- printf("%I64d\n",query(,N,));
- }
- else if(tid[root]>=tid[lca]&&tid[root]<=end[lca]){
- long long ans=;
- X=,Y=N;
- ans=query(,N,);
- int temp=get_son(lca);
- X=tid[temp],Y=end[temp];
- ans-=query(,N,);
- printf("%I64d\n",ans);
- }
- else{
- X=tid[lca],Y=end[lca];
- printf("%I64d\n",query(,N,));
- }
- }
- }
- return ;
- }
codeforces 916E Jamie and Tree dfs序列化+线段树+LCA的更多相关文章
- CodeForces 620E:New Year Tree(dfs序+线段树)
E. New Year Treetime limit per test3 secondsmemory limit per test256 megabytesinputstandard inputout ...
- codeforces 620E. New Year Tree dfs序+线段树+bitset
题目链接 给一棵树, 每个节点有颜色, 两种操作, 一种是将一个节点的子树全都染色成c, 一种是查询一个节点的子树有多少个不同的颜色, c<=60. 每个节点一个bitset维护就可以. #in ...
- POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和)
POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和) 题意分析 卡卡屋前有一株苹果树,每年秋天,树上长了许多苹果.卡卡很喜欢苹果.树上有N个节点,卡卡给他们编号1到N,根 ...
- Codeforces Round #225 (Div. 2) E. Propagating tree dfs序+-线段树
题目链接:点击传送 E. Propagating tree time limit per test 2 seconds memory limit per test 256 megabytes inpu ...
- Codeforces 916E Jamie and Tree (换根讨论)
题目链接 Jamie and Tree 题意 给定一棵树,现在有下列操作: $1$.把当前的根换成$v$:$2$.找到最小的同时包含$u$和$v$的子树,然后把这棵子树里面的所有点的值加$x$: ...
- POJ3321 - Apple Tree DFS序 + 线段树或树状数组
Apple Tree:http://poj.org/problem?id=3321 题意: 告诉你一棵树,每棵树开始每个点上都有一个苹果,有两种操作,一种是计算以x为根的树上有几个苹果,一种是转换x这 ...
- BZOJ - 2588 Spoj 10628. Count on a tree (可持久化线段树+LCA/树链剖分)
题目链接 第一种方法,dfs序上建可持久化线段树,然后询问的时候把两点之间的所有树链扒出来做差. #include<bits/stdc++.h> using namespace std; ...
- 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 ...
- Codeforces 916E(思维+dfs序+线段树+LCA)
题面 传送门 题目大意:给定初始根节点为1的树,有3种操作 1.把根节点更换为r 2.将包含u,v的节点的最小子树(即lca(u,v)的子树)所有节点的值+x 3.查询v及其子树的值之和 分析 看到批 ...
随机推荐
- PDO访问其他数据库操作及作用
PDO的作用 PDO<!--数据访问抽象层--><!--1.可以访问其他数据库--><!--2.具有事务功能--><!--3.带有预处理语句功能(防止SQL注 ...
- Java class对象说明 Java 静态变量声明和赋值说明
先看下JDK中的说明: java.lang.Object java.lang.Class<T> Instances of the class Class represent cla ...
- [Windows Server 2012] 杰奇CMS安全设置
★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com ★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频. ★ 本节我们将带领大家:JIEQI ...
- 测试edit中数据是否合法
void XyModal::OnEnKillfocusEdit1() { // TODO: 在此添加控件通知处理程序代码 CString cText; GetDlgItemText(IDC_EDIT1 ...
- 【原】Python学习_Django搭建环境及创建第一个项目
1.Window 平台安装 Python 下载安装包 https://www.python.org/downloads/windows/ 2.Pyhton环境变量配置 右键点击"计算机 ...
- 控制台输出(System.out.printf)的使用
一. 介绍 System.out.printf 与 C语言中的 printf 使用方法类似,可以向控制台(Console) 输出指定格式的内容.使用 System.out.printf 的方法比使 ...
- 39.date hitogram基础知识
主要知识点: date hitogram之统计每月电视销量 上一节讲到histogram,他是以数值进行分组.本节讲到以日期进行bucket分组操作,也就是说把连续的日期变成离散的日期区间,然 ...
- 8 pandas模块,多层索引
1 创建多层索引 1)隐式构造 最常见的方法是给DataFrame构造函数的index参数传递两个或更多的数组 · Series也可以创建多层索引 ...
- redis高可用,保证高并发
目录 redis如何通过读写分离来承载读请求QPS超过10万+ redis replication以及master持久化对主从架构的安全意义 redis主从复制原理.断点续传.无磁盘化复制.过期key ...
- PatentTips - Substitute virtualized-memory page tables
BACKGROUND Many computer systems utilize virtualized memory for security, stability and/or other pur ...