[ZJOI2008]树的统计(树链剖分)
Description
一棵树上有 n 个节点,编号分别为 1 到 n,每个节点都有一个权值 w。我们将以下面的形式来要求你对这棵树完成一些操作:
I. CHANGE u t : 把结点 u 的权值改为 t。
II. QMAX u v: 询问从点 u 到点 v 的路径上的节点的最大权值。
III. QSUM u v: 询问从点 u 到点 v 的路径上的节点的权值和。注意:从点 u到点 v 的路径上的节点包括 u 和 v 本身。
输入格式
输入文件的第一行为一个整数 n,表示节点的个数。
接下来 n-1 行,每行 2 个整数 a 和 b,表示节点 a 和节点 b 之间有一条边相连。
接下来一行 n 个整数,第 i 个整数 w_i 表示节点 i 的权值。接下来 1 行,为一个整数 q,表示操作的总数。
接下来 q行,每行一个操作,以 CHANGE u t 或者 QMAX u v 或者 QSUM u v 的形式给出。
输出格式
对于每个 QMAX 或者 QSUM 的操作,每行输出一个整数表示要求输出的结果。
Solution
模板题。。。
Code
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
const int N=3e4+;
vector <int> link[N];
struct node
{
int l,r,lc,rc,sum,ma;
}f[N*];
int fa[N],top[N],son[N],dfn[N],size[N],n,q,a,b,cnt,tot,rt,d[N],deep[N];
char s[];
void dfs1(int u,int fat)
{
size[u]=,fa[u]=fat,deep[u]=deep[fat]+;
int siz=link[u].size();
for(int i=;i<siz;i++)
{
int v=link[u][i];
if(v==fa[u]) continue;
dfs1(v,u),size[u]+=size[v];
if(son[u]== || size[son[u]]<size[v]) son[u]=v;
}
}
void dfs2(int u)
{
dfn[u]=++cnt;
if(son[u])
{
top[son[u]]=top[u],dfs2(son[u]);
int siz=link[u].size();
for(int i=;i<siz;i++)
{
int v=link[u][i];
if(v==fa[u] || v==son[u]) continue;
top[v]=v,dfs2(v);
}
}
}
void push_up(int g)
{
int lc=f[g].lc,rc=f[g].rc;
if(lc==) return ;
f[g].ma=max(f[lc].ma,f[rc].ma);
f[g].sum=f[lc].sum+f[rc].sum;
}
void build(int &g,int l,int r)
{
g=++tot,f[g].l=l,f[g].r=r;
if(l==r)
{
f[g].ma=f[g].sum=d[l];
return ;
}
int mid=(l+r)>>;
build(f[g].lc,l,mid);
build(f[g].rc,mid+,r);
push_up(g);
}
void change(int g,int x,int y)
{
if(f[g].l==f[g].r)
f[g].ma=f[g].sum=y;
else
{
int mid=(f[g].l+f[g].r)>>;
if(x<=mid) change(f[g].lc,x,y);
else change(f[g].rc,x,y);
push_up(g);
}
}
int get_max(int g,int l,int r)
{
if(f[g].l>=l && f[g].r<=r)
return f[g].ma;
else
{
int mid=(f[g].l+f[g].r)>>;
if(r<=mid) return get_max(f[g].lc,l,r);
else if(l>mid) return get_max(f[g].rc,l,r);
else return max(get_max(f[g].lc,l,mid),get_max(f[g].rc,mid+,r));
}
}
int get_sum(int g,int l,int r)
{
if(f[g].l>=l && f[g].r<=r)
return f[g].sum;
else
{
int mid=(f[g].l+f[g].r)>>;
if(r<=mid) return get_sum(f[g].lc,l,r);
else if(l>mid) return get_sum(f[g].rc,l,r);
else return get_sum(f[g].lc,l,mid)+get_sum(f[g].rc,mid+,r);
}
}
int Get_sum(int x,int y)
{
int ans=;
int px=top[x],py=top[y];
while(px!=py)
if(deep[px]>deep[py])
{
ans+=get_sum(rt,dfn[px],dfn[x]);
x=fa[px],px=top[x];
}
else
{
ans+=get_sum(rt,dfn[py],dfn[y]);
y=fa[py],py=top[y];
}
if(dfn[x]<dfn[y]) ans+=get_sum(rt,dfn[x],dfn[y]);
else ans+=get_sum(rt,dfn[y],dfn[x]);
return ans;
}
int Get_max(int x,int y)
{
int ans=-<<;
int px=top[x],py=top[y];
while(px!=py)
if(deep[px]>deep[py])
{
ans=max(ans,get_max(rt,dfn[px],dfn[x]));
x=fa[px],px=top[x];
}
else
{
ans=max(ans,get_max(rt,dfn[py],dfn[y]));
y=fa[py],py=top[y];
}
if(dfn[x]<dfn[y]) ans=max(ans,get_max(rt,dfn[x],dfn[y]));
else ans=max(ans,get_max(rt,dfn[y],dfn[x]));
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=;i<n;i++)
{
scanf("%d%d",&a,&b);
link[a].push_back(b);
link[b].push_back(a);
}
dfs1(,),top[]=,dfs2();
for(int i=;i<=n;i++)
scanf("%d",&d[dfn[i]]);
build(rt,,cnt);
scanf("%d",&q);
//CHANGE u t :把节点 u权值改为 t;
//QMAX u v :询问点 u到点 v路径上的节点的最大权值;
//QSUM u v :询问点 u到点 v路径上的节点的权值和。
while(q--)
{
scanf("%s",s);
scanf("%d%d",&a,&b);
if(s[]=='C')
change(rt,dfn[a],b);
else if(s[]=='M')
printf("%d\n",Get_max(a,b));
else printf("%d\n",Get_sum(a,b));
}
return ;
}
[ZJOI2008]树的统计(树链剖分)的更多相关文章
- BZOJ 1036: [ZJOI2008]树的统计Count-树链剖分(点权)(单点更新、路径节点最值、路径求和)模板,超级认真写了注释啊啊啊
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 23015 Solved: 9336[Submit ...
- 树的统计Count---树链剖分
NEFU专项训练十和十一——树链剖分 Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t ...
- BZOJ1036[ZJOI2008]树的统计——树链剖分+线段树
题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v ...
- [ZJOI2008]树的统计——树链剖分
本题是一个树链剖分裸题,由于比较菜,老是RE,后来发现是因为使用了全局变量. /************************************************************ ...
- [luogu P2590 ZJOI2008] 树的统计 (树链剖分)
题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u ...
- luoguP2590 [ZJOI2008]树的统计(树链剖分)
luogu P2590 [ZJOI2008]树的统计 题目 #include<iostream> #include<cstdlib> #include<cstdio> ...
- 洛谷P2590 [ZJOI2008] 树的统计 [树链剖分]
题目传送门 树的统计 题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t ...
- BZOJ 1036 树的统计-树链剖分
[ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 12904 Solved: 5191[Submit][Status ...
- BZOJ-1036 树的统计Count 链剖线段树(模板)=(树链剖分+线段树)
潇爷昨天刚刚讲完...感觉得还可以...对着模板打了个模板...还是不喜欢用指针.... 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Lim ...
- bzoj1036 树的统计 树链剖分模板
题意:给出树上任意两点,求路径上的值的和与最大值,带单点修改操作 树链剖分思路: 1.对树进行dfs求出点的深度和父亲节点,然后求出轻重儿子(重儿子就是点最多的那个子树,其余都是轻儿子),用一个son ...
随机推荐
- com.netflix.discovery.DiscoveryClient : Completed shut down of DiscoveryClient
启动报错:com.netflix.discovery.DiscoveryClient : Completed shut down of DiscoveryClient 解决方案: 添加web主件 ...
- C# 实现多线程
1.System.Threading命名空间 System.Threading命名空间提供了使得可以多线程编程的类和接口 其中 (1)Thread类构成了C#多线程编程的支柱,他用于创建并控制线程 ...
- MySQL数据库性能优化:表、索引、SQL等
一.MySQL 数据库性能优化之SQL优化 注:这篇文章是以 MySQL 为背景,很多内容同时适用于其他关系型数据库,需要有一些索引知识为基础 优化目标 减少 IO 次数IO永远是数据库最容易瓶颈的地 ...
- linux-head、tail、sort、uniq、pstree、ps
1.head 默认查看文件前10行 head -7 /etc/yum.conf -n num -n7代表查看文件前7行 2.tail 默认查看文件的后10行 tail -7 /etc/yum.conf ...
- $bzoj4237$稻草人 $cdq$分治
正解:$cdq$分治 解题报告: 传送门$QwQ$ $umm$总感觉做过这题的亚子,,,? 先把坐标离散化,然后把所有点先按$x$排序$QwQ$,然后用类似平面最近点对的方法,先分别解决$mid$两侧 ...
- SpringBoor与SpringCloud的关系
SpringBoot是一个快速开发的框架,能够快速的整合第三方框架.简化XML配置,全部采用注解形式,内置Web服务器(如Tomcat等),帮助开发者能够实现快速开发,SpringBoot Web控制 ...
- echarts设置数据在轴线上显示
项目中遇到数据需要在右侧显示,如图,直接上代码: 1.需要在哪个轴上显示 就把那个轴写成一个数组 2.分别设置一下定位和数据即可(如下图红色部分) yAxis: [ { type: 'categor ...
- 原生javascript实现选项卡(基础版)
一.实现原理 1.主要运用“排他思想”,在设置当前元素前,先把相应元素恢复到默认状态 2.给相应元素添加下标的应用 二.代码展示 <!DOCTYPE html> <html> ...
- es5中数组的遍历方法
//for循环 const arr = [1,2,3,4,5] for(let i = 0; i < arr.length; i++){ if(arr[i] === 2){ //break // ...
- 区间dp - 送外卖
When we are focusing on solving problems, we usually prefer to stay in front of computers rather tha ...