[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 ...
随机推荐
- linux包之下载curl-wget
[root@localhost ~]# rpm -qa|grep curllibcurl-7.19.7-37.el6_4.x86_64python-pycurl-7.19.0-8.el6.x86_64 ...
- 开发API整理(转)
附送一个 android 源码 查看地址 http://grepcode.com/project/repository.grepcode.com/java/ext/com.google.android ...
- 在Linux CentOS下如何安装tar.gz和RPM软件包
1.安装tar.gz软件包: 在Linuxr(Centos下)如何安装tar.gz软件包,该方式实质上就是源代码安装方式,具体如下: 在Linux中使用wget命令下载要安装的文件,命令格式如下:wg ...
- C# 初识接口 Interface
什么是接口? 接口(interface)用来定义一种程序的协定.实现接口的类或者结构要与接口的定义严格一致.有了这个协定,就可以抛开编程语言的限制(理论上).C#接口可以从多个基接口继承,而类或结构可 ...
- $Poj1821\ Fence\ $单调队列优化$DP$
Poj Acwing Description 有N块木板等待被M个工匠粉刷,每块木板至多被刷一次.第i个工匠要么不粉刷,要么粉刷包含木块Si的,长度不超过Li的连续的一段木板,每粉刷一块可以得到P ...
- Java容器知识总结
剖析面试最常见问题之Java集合框架 说说List,Set,Map三者的区别? List(对付顺序的好帮手): List接口存储一组不唯一(可以有多个元素引用相同的对象),有序的对象 Set(注重独一 ...
- java实现单向循环链表
链表图解 带头结点的链表: 不带头结点的链表: 区别 带头结点的链表容易代码实现 不带头结点的容易实现循环链表和双向链表 代码的实现 (增减 删除) 节点实现: public class node { ...
- 「Vijos 1285」「OIBH杯NOIP2006第二次模拟赛」佳佳的魔法药水
佳佳的魔法药水 背景 发完了k张照片,佳佳却得到了一个坏消息:他的MM得病了!佳佳和大家一样焦急万分!治好MM的病只有一种办法,那就是传说中的0号药水--怎么样才能得到0号药水呢?你要知道佳佳的家境也 ...
- Redis-CAP定理和BASE理论(二)
CAP理论概述 1998 年来自柏克莱加州大学的计算机科学家 埃里克.布鲁尔(Eric Brewer) 提出分布式系统的三个基本指标:Consistency(一致性).Availability(可用性 ...
- Ado.net总结-Command(指挥官)
Command 概述 在 System.Data.SqlClient 命名空间下,对应的 Command 类为 SqlCommand,在创建 SqlCommand 实例前必须已经创建了与数据库的连接. ...