[HAOI2015]树上操作(luogu)

Description

题目描述

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:

  • 操作 1 :把某个节点 x 的点权增加 a 。
  • 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
  • 操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

输入格式

第一行包含两个整数 N, M 。表示点数和操作数。
接下来一行 N 个整数,表示树中节点的初始权值。
接下来 N-1 行每行两个正整数 from, to , 表示该树中存在一条边 (from, to) 。
再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

输出格式

对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

Solution

操作 1:线段树中点dfn[x]加a;

操作 2:由树链剖分遍历的顺序可知任何一棵子树中节点的dfs序<=子树的根的dfs序,

且最大的dfs序=子树的根的dfs序+子树的大小-1,于是可以直接在线段树上操作;

操作 3:简化版树剖求和模板

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
const int N=1e5+;
struct node
{
int l,r,lc,rc;
long long sum,delay;
}f[N*];
int n,u,v,m,deep[N],tot,si[N],top[N],d[N],t,
fa[N],dfn[N],cnt,rt,son[N],re[N],opt,x;
long long a;
char s[];
vector <int> link[N];
void dfs1(int u,int f)
{
si[u]=,fa[u]=f,deep[u]=deep[f]+;
int size=link[u].size();
for(int i=;i<size;i++)
{
int v=link[u][i];
if(v!=f)
{
dfs1(v,u);
si[u]+=si[v];
if(son[u]== || si[son[u]]<si[v]) son[u]=v;
}
}
}
void dfs2(int u,int f)
{
dfn[u]=++tot,re[tot]=u;
if(son[u]!=)
{
top[son[u]]=top[u],dfs2(son[u],u);
int size=link[u].size();
for(int i=;i<size;i++)
{
int v=link[u][i];
if(v!=f && v!=son[u])
top[v]=v,dfs2(v,u);
}
}
}
long long gel(int g)
{
return f[g].r-f[g].l+;
}
void push_up(int g)
{
int lc=f[g].lc,rc=f[g].rc;
if(lc==) return ;
f[g].sum=f[lc].sum+f[rc].sum+gel(g)*f[g].delay;
}
void push_down(int g)
{
int lc=f[g].lc,rc=f[g].rc;
if(lc== || f[g].delay==) return ;
f[lc].delay+=f[g].delay,f[rc].delay+=f[g].delay;
f[lc].sum+=gel(lc)*f[g].delay,f[rc].sum+=gel(rc)*f[g].delay;
f[g].delay=;
}
void build(int &g,int l,int r)
{
g=++cnt;
f[g].l=l,f[g].r=r;
if(l==r)
{
f[g].sum=d[re[l]];
return ;
}
int mid=(l+r)>>;
build(f[g].lc,l,mid);
build(f[g].rc,mid+,r);
push_up(g);
}
void add(int g,int l,int r,int k)
{
if(f[g].l>=l && f[g].r<=r)
f[g].sum+=gel(g)*k,f[g].delay+=k;
else
{
int mid=(f[g].l+f[g].r)/;
if(r<=mid) add(f[g].lc,l,r,k);
else if(l>mid) add(f[g].rc,l,r,k);
else add(f[g].lc,l,mid,k),add(f[g].rc,mid+,r,k);
push_up(g);
}
}
long long get(int g,int l,int r)
{
if(f[g].l>=l && f[g].r<=r)
return f[g].sum;
else
{
push_down(g);
int mid=(f[g].l+f[g].r)/;
if(r<=mid) return get(f[g].lc,l,r);
else if(l>mid) return get(f[g].rc,l,r);
else return get(f[g].lc,l,mid)+get(f[g].rc,mid+,r);
}
}
long long Get(int x)
{
long long sum=;
while(x!=)
{
sum+=get(rt,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
return sum;
}
//操作 1 :把某个节点 x 的点权增加 a 。
//操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
//操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
scanf("%d",&d[i]);
for(int i=;i<n;i++)
{
scanf("%d%d",&u,&v);
link[u].push_back(v);
link[v].push_back(u);
}
dfs1(,);
top[]=,dfs2(,);
build(rt,,tot);
while(m--)
{
scanf("%d%d",&opt,&x);
if(opt==) printf("%lld\n",Get(x));
else
{
scanf("%lld",&a);
if(a!=)
{
if(opt==) add(rt,dfn[x],dfn[x],a);
else if(opt==) add(rt,dfn[x],dfn[x]+si[x]-,a);
}
}
}
return ;
}

[HAOI2015]树上操作(树链剖分)的更多相关文章

  1. bzoj4034[HAOI2015]树上操作 树链剖分+线段树

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 6163  Solved: 2025[Submit][Stat ...

  2. bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4352  Solved: 1387[Submit][Stat ...

  3. 【BZOJ4034】[HAOI2015]树上操作 树链剖分+线段树

    [BZOJ4034][HAOI2015]树上操作 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 ...

  4. BZOJ4034 [HAOI2015]树上操作 树链剖分

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4034 题意概括 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三 ...

  5. P3178 [HAOI2015]树上操作 树链剖分

    这个题就是一道树链剖分的裸题,但是需要有一个魔性操作___编号数组需要开longlong!!!震惊!真的神奇. 题干: 题目描述 有一棵点数为 N 的树,以点 为根,且树点有边权.然后有 M 个操作, ...

  6. BZOJ4034[HAOI2015]树上操作——树链剖分+线段树

    题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都 ...

  7. bzoj 4034: [HAOI2015]树上操作——树链剖分

    Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中 ...

  8. BZOJ 4034[HAOI2015]树上操作(树链剖分)

    Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点 ...

  9. bzoj4034 [HAOI2015]树上操作——树链剖分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4034 树剖裸题: 一定要注意 long long !!! update 的时候别忘了 pus ...

  10. [HAOI2015]树上操作-树链剖分

    #include<bits/stdc++.h> using namespace std; const int maxn = 1e6+5; #define mid ((l+r)>> ...

随机推荐

  1. .Net Core解除文件上传大小限制

    一共要修改两处地方: \Startup.cs public void ConfigureServices(IServiceCollection services) { services.AddMvc( ...

  2. [vue/no-parsing-error] Parsing error: x-invalid-end-tag.eslint-plugin-vue

    [vue/no-parsing-error] Parsing error: x-invalid-end-tag.eslint-plugin-vue   解决方案:vscode里面选择设置->搜索 ...

  3. git authentication failed for 或 fatal:not a git repository

    第一种解决 (我的是第一种解决) github上更改密码之后,我在本地操作git发现出错,错误代码如上,在网上搜了一圈,没有解决问题,后发现需要进行如下操作: 进入控制面板>用户账号>凭据 ...

  4. LeetCode150_Evaluate Reverse Polish Notation评估逆波兰表达式(栈相关问题)

    题目: Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are+, ...

  5. vagrant在windows下的安装和配置(二)

    在(一)中安装和配置好后 框框中的信息是登录vagrant up后的系统用的 我这里登录用的是xshell-----下载一个xshell然后安装 打开xshell 按确定之后生成一个新的会话,然后登录 ...

  6. 解析crash

    命令行 1.查找 symbolicatecrash find /Applications/Xcode.app -name symbolicatecrash -type f 2.此时会出现一个路径 sy ...

  7. spring注解之@Import注解的三种使用方式

    目录 1.@Import注解须知 2.@Import的三种用法 3.@Import注解的三种使用方式总结 @ 1.@Import注解须知 1.@Import只能用在类上 ,@Import通过快速导入的 ...

  8. knn识别简单验证码

    参考 https://www.biaodianfu.com/knn-captcha-recognition.html 内容大致一样,只是根据自己的想法加入了一些改动 KNN(k近邻算法) 算法原理请看 ...

  9. $CH5105\ Cookies$ 线性$DP+$贪心

    CH 是很有趣的一道题 : ) Sol 第一反应就是f[i][j]表示前i个小朋友分j块饼干的最小怨气值 但是一个孩子所产生的怨气值并不固定,它与其他孩子获得饼干的情况有关 这里可以用到一个贪心,就是 ...

  10. $POJ1015\ Jury\ Compromise\ Dp$/背包

    洛谷传送门 $Sol$ 这是一道具有多个“体积维度”的$0/1$背包问题. 把$N$个候选人看做$N$个物品,那么每个物品有如下三种体积: 1.“人数”,每个候选人的“人数”都是$1$,最终要填满容积 ...