[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 ...
随机推荐
- Cisco DNA-C POC环境配置
Step1:在DNA-C上创建Site,本例创建Global->China->WangJiang->20 F如下图: Step2:配置fusion区域的AAA和NTP等信息,如下图: ...
- 010.MFC_Progress
一.建立名为processCtrl的MFC工程,添加Progress Control 和 button控件.修改button Caption属性为start,ID属性为IDC_BTN_START 为进 ...
- 用VISA工具驱动继电器外设
1.驱动方式:TCP 2.开发过程 第一步:外设识别 TCP方式将继电器插上网线后,并不能像串口一样自动识别到这个外设,需要手动连接.打开NI MAX后,右击设备与接口,然后点击新建,双击VISA T ...
- vc++调用msscript.ocx解析实现C++与JavaScript脚本交互
ScriptControl接口 属性名称 类型 备注 AllowUI BOOL 检测是否允许运行用户的接口元素.如果为False,则诸如消息框之类的界面元素不可见. CodeObject Object ...
- JVM探秘:垃圾收集算法
本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. 垃圾收集算法 垃圾收集算法主要有标记-清除算法.复制算法.标记-整理算法.分代收集算法 ...
- 查看磁盘型号和内存及raid信息
1.查看磁盘型号 工具:smartmontools #smartctl --help #smartctl --all /dev/sda -d megarid,1 (第一块磁盘的信息) #smartct ...
- js判断各种类型
js的六种基本类型:Object,Boolean,Number,String,Undefined,Null; Object中又有:Function,Array,Date... 如何判断数据类型? Ob ...
- Mybatis-plus 实体类继承关系 插入默认值
在实际开发中,会定义一些公共字段,而这些公共字段,一般都是在进行操作的时候由程序自动将默认值插入.而公共的字段一般会被封装到一个基础的实体类中,同时实体类中会实现相应的getter setter 方法 ...
- vue传值(父子传值,非父子传值)
vue组件传值,分为父子传值和非父子传值,父子传值又分为父传子和子传父. 组件之间的传值,实现了数据的联动,是从操作Dom到操作数据一个跳转性的突破,在学习vue双向绑定原理之后, 这种观念就应该继续 ...
- 小白学 Python 爬虫(39): JavaScript 渲染服务 scrapy-splash 入门
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...