题目描述
一棵树上有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之间。

题解:我懒得写一棵线段树两种操作了,所以索性写了两棵线段树,一棵 清蒸  求区间最大值,一棵红烧 求区间和

单点修改的时候,就同时修改两棵树。查询就是最经典的路径查询啦~

代码写了4k,还暗自窃喜自己终于写了一长度4k的代码,回去一看,什么鬼,我树剖模板题都写的比这个长?

也是醉了,代码如下:

#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson root<<1
#define rson root<<1|1
using namespace std; struct node
{
int m,l,r;
} tr_sum[],tr_max[];
int size[],deep[],fa[],son[],id[],top[],w[],c[],cnt;
vector<int> g[]; void push_up_sum(int root)
{
tr_sum[root].m=tr_sum[lson].m+tr_sum[rson].m;
} void push_up_max(int root)
{
tr_max[root].m=max(tr_max[lson].m,tr_max[rson].m);
} void build_sum(int root,int l,int r)
{
if(l==r)
{
tr_sum[root].l=l;
tr_sum[root].r=r;
tr_sum[root].m=w[l];
return ;
}
tr_sum[root].l=l;
tr_sum[root].r=r;
int mid=(l+r)>>;
build_sum(lson,l,mid);
build_sum(rson,mid+,r);
push_up_sum(root);
} void build_max(int root,int l,int r)
{
if(l==r)
{
tr_max[root].l=l;
tr_max[root].r=r;
tr_max[root].m=w[l];
return ;
}
tr_max[root].l=l;
tr_max[root].r=r;
int mid=(l+r)>>;
build_max(lson,l,mid);
build_max(rson,mid+,r);
push_up_max(root);
} void update(int root,int x,int val)
{
if(x==tr_sum[root].l&&x==tr_sum[root].r)
{
tr_sum[root].m=val;
tr_max[root].m=val;
return ;
}
int mid=(tr_sum[root].l+tr_sum[root].r)>>;
if(x>mid)
{
update(rson,x,val);
}
else
{
update(lson,x,val);
}
push_up_sum(root);
push_up_max(root);
} int query_sum(int root,int l,int r)
{
if(l==tr_sum[root].l&&r==tr_sum[root].r)
{
return tr_sum[root].m;
}
int mid=(tr_sum[root].l+tr_sum[root].r)>>;
if(l>mid)
{
return query_sum(rson,l,r);
}
else
{
if(r<=mid)
{
return query_sum(lson,l,r);
}
else
{
return query_sum(lson,l,mid)+query_sum(rson,mid+,r);
}
}
} int query_max(int root,int l,int r)
{
if(l==tr_max[root].l&&r==tr_max[root].r)
{
return tr_max[root].m;
}
int mid=(tr_max[root].l+tr_max[root].r)>>;
if(l>mid)
{
return query_max(rson,l,r);
}
else
{
if(r<=mid)
{
return query_max(lson,l,r);
}
else
{
return max(query_max(lson,l,mid),query_max(rson,mid+,r));
}
}
} void dfs1(int now,int f,int dep)
{
fa[now]=f;
deep[now]=dep;
size[now]=;
int maxson=-;
for(int i=; i<g[now].size(); i++)
{
if(g[now][i]==f)
{
continue;
}
dfs1(g[now][i],now,dep+);
size[now]+=size[g[now][i]];
if(size[g[now][i]]>maxson)
{
son[now]=g[now][i];
maxson=size[g[now][i]];
}
}
} void dfs2(int now,int topf)
{
id[now]=++cnt;
w[cnt]=c[now];
top[now]=topf;
if(!son[now])
{
return ;
}
dfs2(son[now],topf);
for(int i=; i<g[now].size(); i++)
{
if(g[now][i]==fa[now]||g[now][i]==son[now])
{
continue;
}
dfs2(g[now][i],g[now][i]);
}
} int path_query_max(int x,int y)
{
int ans=-;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
{
swap(x,y);
}
ans=max(ans,query_max(,id[top[x]],id[x]));
x=fa[top[x]];
}
if(deep[x]>deep[y])
{
swap(x,y);
}
ans=max(ans,query_max(,id[x],id[y]));
return ans;
} int path_query_sum(int x,int y)
{
int ans=;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
{
swap(x,y);
}
ans+=query_sum(,id[top[x]],id[x]);
x=fa[top[x]];
}
if(deep[x]>deep[y])
{
swap(x,y);
}
ans+=query_sum(,id[x],id[y]);
return ans;
} int main()
{
int n,m;
scanf("%d",&n);
for(int i=; i<=n-; i++)
{
int from,to;
scanf("%d%d",&from,&to);
g[from].push_back(to);
g[to].push_back(from);
}
for(int i=; i<=n; i++)
{
scanf("%d",&c[i]);
}
dfs1(,,);
dfs2(,);
build_sum(,,n);
build_max(,,n);
scanf("%d",&m);
char s[];
int u,v;
for(int i=; i<=m; i++)
{
scanf("\n%s %d %d",s,&u,&v);
if(s[]=='C')
{
update(,id[u],v);
}
if(s[]=='Q')
{
if(s[]=='S')
{
printf("%d\n",path_query_sum(u,v));
}
if(s[]=='M')
{
printf("%d\n",path_query_max(u,v));
}
}
}
}

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

  1. 洛谷——P2590 [ZJOI2008]树的统计(树链剖分模板练手)

    P2590 [ZJOI2008]树的统计 I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问 ...

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

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

  3. 洛谷P2590 [ZJOI2008]树的统计 题解 树链剖分+线段树

    题目链接:https://www.luogu.org/problem/P2590 树链剖分模板题. 剖分过程要用到如下7个值: fa[u]:u的父节点编号: dep[u]:u的深度: size[u]: ...

  4. [洛谷P2590][ZJOI2008]树的统计

    题目大意:一棵树,支持三个操作, $CHANGE\;u\;t:$ 把结点$u$的权值改为$t$ $QMAX\;u\;v:$ 询问从点$u$到点$v$的路径上的节点的最大权值 $QSUM\;u\;v:$ ...

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

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

  6. 洛谷 P4292 - [WC2010]重建计划(长链剖分+线段树)

    题面传送门 我!竟!然!独!立!A!C!了!这!道!题!incredible! 首先看到这类最大化某个分式的题目,可以套路地想到分数规划,考虑二分答案 \(mid\) 并检验是否存在合法的 \(S\) ...

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

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

  8. 洛谷 P2590 [ZJOI2008]树的统计

    大家好,我非常喜欢暴力数据结构,于是我用块状树过了这道题目 题目: 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE ...

  9. 洛谷——P2590 [ZJOI2008]树的统计

    https://www.luogu.org/problem/show?pid=2590#sub 题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这 ...

随机推荐

  1. 漫谈Java IO之基础篇

    Java的网络编程如果不是专门搞服务器性能开发或者消息分发,几乎可能涉及不到.但是它却是面试找工作必问的一个知识点,涵盖的知识体系也非常广泛,从Java底层IO原理到操作系统内核组成,再到网络TCP. ...

  2. 20.C++- "&&","||"逻辑重载操作符的缺陷、","逗号重载操作符的分析

    "&&","||"逻辑重载操作符的缺陷 大家,都知道"&&","||"拥有"短 ...

  3. KVM之十:虚拟机在线添加网卡

    1.查看原有网卡信息 #virsh domiflist snale Interface Type Source Model MAC ---------------------------------- ...

  4. Android类参考---SQLiteOpenHelper

    public 抽象类 SQLiteOpenHelper 继承关系 java.lang.Object |____android.database.sqlite.SQLiteOpenHelper 类概要 ...

  5. <经验杂谈>C#使用AES加密解密的简单介绍

    AES 算法是基于置换和代替的.置换是数据的重新排列,而代替是用一个单元数据替换另一个.AES 使用了几种不同的技术来实现置换和替换. 以下是我自己用c#研究出来算法Code: /// <sum ...

  6. pip安装selenium报错:Read timed out

    今天打算把selenium降级重新安装,发现安装时总是失败,报如下错误: raise ReadTimeoutError(self._pool, None, 'Read timed out.') pip ...

  7. C语言博客作业--数据类型

    一.PTA实验作业 题目1:7-8 判断合法标识符 1. 本题PTA提交列表 2. 设计思路 1.定义整数型变量repeat和i来存放判断字符串是否为合法标识符的次数,定义字符型ch来存放读取的字符 ...

  8. C语言--第一周作业(更改)

    *********************学习总结********************* 1.所用词典: 2.Git截图: *********************遇到的问题和解决方法***** ...

  9. 张金禹 C语言--第0次作业

    1:在填报专业的时候,我也犹豫了很久,但最后还是选择了计算机专业.因为在上大学之前我就对编程.设计等有浓厚的兴趣,但繁重的高中学习任务使我没有过多的去关注,所以我选择了计算机专业去培养我在这方面的兴趣 ...

  10. 201621123043 《Java程序设计》第2周学习总结

    1.本周学习总结 使用jdk文档查阅函数功能及代码 用switch语句是在每个case中可能在第一行是sc.nextLine;来给回车赋值: 在使用循环的时候要注意循环返回的条件,否则陷入死循环可能会 ...