题目描述

一棵树上有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个整数wi表示节点i的权值。

接下来1行,为一个整数q,表示操作的总数。

接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。

输出格式:

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

输入输出样例

输入样例#1:

4

1 2

2 3

4 1

4 2 1 3

12

QMAX 3 4

QMAX 3 3

QMAX 3 2

QMAX 2 3

QSUM 3 4

QSUM 2 1

CHANGE 1 5

QMAX 3 4

CHANGE 3 6

QMAX 3 4

QMAX 2 4

QSUM 3 4

输出样例#1:

4

1

2

2

10

6

5

6

5

16

说明

对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

树链剖分模板。。。

code:

//By Menteur_Hxy
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#define ll long long
#define f(a,b,c) for(int a=b;a<=c;a++)
using namespace std; inline ll rd() {
ll x=0,fla=1; char c=' ';
while(c>'9' || c<'0') {if(c=='-') fla=-fla; c=getchar();}
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*fla;
} inline void out(ll x){
int a[25],wei=0;
if(x<0) putchar('-'),x=-x;
for(;x;x/=10) a[++wei]=x%10;
if(wei==0){ puts("0"); return;}
for(int j=wei;j>=1;--j) putchar('0'+a[j]);
putchar('\n');
} const int MAX=300100;//直接开了十倍qwq
const int INF=0x3f3f3f3f;
int n,cnt,N; int head[MAX],W[MAX],size[MAX],h[MAX],fa[MAX],son[MAX];
//W 点权 size 树的大小 h 深度 fa 父亲 son 重儿子 int num[MAX],top[MAX],tree[MAX],maxn[MAX],sumn[MAX];
//num 在线段树编号 top 链最上面的点 tree 线段树编号对应的点 struct edges{
int next,to;
}edge[MAX]; void add(int a,int b) {
edge[++cnt]=(edges) {head[a],b}; head[a]=cnt;
edge[++cnt]=(edges) {head[b],a}; head[b]=cnt;
} void dfs1(int u,int pre,int dep) {
size[u]=1; h[u]=dep; fa[u]=pre;//init
int mason=0;
for(int i=head[u];i;i=edge[i].next)
if(edge[i].to!=pre) {
int v=edge[i].to;
dfs1(v,u,dep+1);
size[u]+=size[v];
if(size[v]>mason) {
mason=size[v];
son[u]=v;
}
}
} void dfs2(int u,int pre) {
if(son[pre]!=u) top[u]=u;
else top[u]=top[pre];
num[u]=++N;
if(son[u]) dfs2(son[u],u);
for(int i=head[u];i;i=edge[i].next)
if(edge[i].to!=pre && edge[i].to !=son[u])
dfs2(edge[i].to,u);
} void build_sum(int cur,int l,int r) {
if(l==r) {
sumn[cur]=W[tree[l]];
return ;
}
int mid=(l+r)>>1;
build_sum(cur<<1,l,mid);
build_sum(cur<<1|1,mid+1,r);
sumn[cur]=sumn[cur<<1]+sumn[cur<<1|1];//update_sum
} void build_max(int cur,int l,int r) {
if(l==r) {
maxn[cur]=W[tree[l]];
return ;
}
int mid=(l+r)>>1;
build_max(cur<<1,l,mid);
build_max(cur<<1|1,mid+1,r);
maxn[cur]=max(maxn[cur<<1],maxn[cur<<1|1]);//update_max
} void po_ch_sum(int cur,int l,int r,int x,int v) {//point_change_sum
if(l==r) {
sumn[cur]=v;
return ;
}
int mid=(l+r)>>1;
if(x<=mid) po_ch_sum(cur<<1,l,mid,x,v);
else po_ch_sum(cur<<1|1,mid+1,r,x,v);
sumn[cur]=sumn[cur<<1]+sumn[cur<<1|1];//update_sum
} void po_ch_max(int cur,int l,int r,int x,int v) {//point_change_max
if(l==r) {
maxn[cur]=v;
return ;
}
int mid=(l+r)>>1;
if(x<=mid) po_ch_max(cur<<1,l,mid,x,v);
else po_ch_max(cur<<1|1,mid+1,r,x,v);
maxn[cur]=max(maxn[cur<<1],maxn[cur<<1|1]);
} int query_sum(int cur,int l,int r,int L,int R) {
if(L<=l&&r<=R) return sumn[cur];
int mid=(l+r)>>1,ans=0;
if(L<=mid) ans+=query_sum(cur<<1,l,mid,L,R);
if(R>mid) ans+=query_sum(cur<<1|1,mid+1,r,L,R);
return ans;
} int query_max(int cur,int l,int r,int L,int R) {
if(L<=l&&r<=R) return maxn[cur];
int mid=(l+r)>>1,ans=-INF;
if(L<=mid) ans=max(ans,query_max(cur<<1,l,mid,L,R));
if(R>mid) ans=max(ans,query_max(cur<<1|1,mid+1,r,L,R));
return ans;
} void INIT() {
dfs1(1,0,1);// size h fa son
dfs2(1,0);//top num
f(i,1,n) tree[num[i]]=i;//tree
//建树:
build_sum(1,1,N);
build_max(1,1,N);
} void solve() {
int q=rd(),a,b,ans=0,f1,f2;
char opt[6];
f(i,1,q) {
scanf("%s",opt);
a=rd(),b=rd(),ans=0;
if(opt[0]=='C') {//HCANGE
po_ch_sum(1,1,N,num[a],b);
po_ch_max(1,1,N,num[a],b);
}
else {
f1=top[a],f2=top[b];
if(opt[1]=='M') ans=-INF;
while(f1!=f2) {
if(h[f1]<h[f2]) {
swap(a,b);
swap(f1,f2);
}
if(opt[1]=='S') ans+=query_sum(1,1,N,num[f1],num[a]);
else ans=max(ans,query_max(1,1,N,num[f1],num[a]));
a=fa[f1];
f1=top[a];
}
if(num[a]>num[b]) swap(a,b);
if(opt[1]=='S') ans+=query_sum(1,1,N,num[a],num[b]);
else ans=max(ans,query_max(1,1,N,num[a],num[b]));
out(ans);
}
}
} int main() {
n=rd();
f(i,1,n-1) add(rd(),rd());
f(i,1,n) W[i]=rd();
INIT();
solve();
return 0;
}

[luogu P2590 ZJOI2008] 树的统计 (树链剖分)的更多相关文章

  1. BZOJ 1036: [ZJOI2008]树的统计Count-树链剖分(点权)(单点更新、路径节点最值、路径求和)模板,超级认真写了注释啊啊啊

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 23015  Solved: 9336[Submit ...

  2. 树的统计Count---树链剖分

    NEFU专项训练十和十一——树链剖分 Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t ...

  3. luoguP2590 [ZJOI2008]树的统计(树链剖分)

    luogu P2590 [ZJOI2008]树的统计 题目 #include<iostream> #include<cstdlib> #include<cstdio> ...

  4. Luogu P2590 [ZJOI2008]树的统计

    最近在学树剖,看到了这题就做了 [ZJOI2008]树的统计 思路 从题面可以知道,这题是树剖题(要求的和模板没什么区别呀喂 就是在普通的树剖上加了一个最大值 所以可以知道就是树剖+特殊的线段树 线段 ...

  5. 洛谷P2590 [ZJOI2008] 树的统计 [树链剖分]

    题目传送门 树的统计 题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t ...

  6. BZOJ1036[ZJOI2008]树的统计——树链剖分+线段树

    题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v ...

  7. [ZJOI2008]树的统计——树链剖分

    本题是一个树链剖分裸题,由于比较菜,老是RE,后来发现是因为使用了全局变量. /************************************************************ ...

  8. BZOJ-1036 树的统计Count 链剖线段树(模板)=(树链剖分+线段树)

    潇爷昨天刚刚讲完...感觉得还可以...对着模板打了个模板...还是不喜欢用指针.... 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Lim ...

  9. BZOJ 1036 树的统计-树链剖分

    [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 12904 Solved: 5191[Submit][Status ...

随机推荐

  1. 洛谷—— P1097 统计数字

    https://www.luogu.org/problem/show?pid=1097 题目描述 某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*10^9).已知不相同的数 ...

  2. 沁园春&#183;咏史

    沁园春·咏史 文/天地尘埃2020 谁是谁非?宋桧连金,武穆饮生. 叹止渴饮鸩.灰飞烟灭:诵传千载:长跪无声. 懿旨朱批?直书秉笔?天地一根秤自衡. 何曾忘! 这英雄千古,犹恨空横! 幽幽何觅忠魂.耻 ...

  3. 金融扫盲-资本市场从天使轮、ABCD轮、风投、到上市圈钱、借壳上市。

    转载请标明出处:http://blog.csdn.net/hu948162999/article/details/47777859 对于金融知识零基础的人进行扫盲,故事浅显易懂.趣味性强. 来之知乎. ...

  4. struts1——静态ActionForm与动态ActionForm

    在struts1中,我们能够使用ActionForm来获取从client端提交上来的数据.并通过action配置中的name属性.将某个ActionForm配置到某次请求应答的Action中.作为本次 ...

  5. C语言播放声音最简单的两种方法

    1. 假设仅须要播放波形文件wav格式的声音,非常easy.仅仅需一句话: PlaySound(TEXT("Data\\1.wav"), NULL, SND_FILENAME | ...

  6. 《游戏脚本的设计与开发》-(RPG部分)3.8 通过脚本来自由控制游戏(一)

    注意:本系列教程为长篇连载无底洞.半路杀进来的朋友,假设看不懂的话.请从第一章開始看起.文章文件夹请点击以下链接. http://blog.csdn.net/lufy_legend/article/d ...

  7. php创建简单的列表页

    php创建简单的列表页 样例 代码 <?php $userInfo[] = array( 'id'=>'1', 'username'=>'fry', 'sex'=>'nan', ...

  8. Node.js:多进程

    ylbtech-Node.js:多进程 1.返回顶部 1. Node.js 多进程 我们都知道 Node.js 是以单线程的模式运行的,但它使用的是事件驱动来处理并发,这样有助于我们在多核 cpu 的 ...

  9. Redis(三)、Redis主从复制

    一.主从复制 主从复制:主节点负责写数据,从节点负责读数据,从而实现读写分离,提高redis的高可用性. 让一个服务器去复制(replicate)另一个服务器,我们称呼被复制的服务器为主节点(mast ...

  10. C# 同步更新系统时间

    前言 在定位用户问题时,发现有些电脑,会出现系统时间不是最新的问题. 可能原因: 取消了勾选服务器时间同步 当前安装的系统,是一个未知来源系统,导致系统时间更新失败 而系统时间不正确,会导致IE选项- ...