题目描述

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

裸的树链剖分。

注意所有的值都要取最大或者最小。

有很小的负边权!

update:数据已加强,下面的代码现在不能通过!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ls k<<1
#define rs k<<1|1
using namespace std;
const int MAXN=1000001;
inline void read(int &n)
{
char c='+';int x=0;bool flag=0;
while(c<'0'||c>'9')
{c=getchar();if(c=='-')flag=1;}
while(c>='0'&&c<='9')
{x=(x<<1)+(x<<3)+c-48,c=getchar();}
flag==1?n=-x:n=x;
}
int n;
int a[MAXN];
int fa[MAXN];// 每一个节点的父亲节点
int deep[MAXN];// 每一个节点的深度
int top[MAXN];// 重链上的顶节点
int son[MAXN];// 每一个点的重儿子
int size[MAXN];// 子节点的数量
int pos[MAXN];// 划分轻重链之后的编号
int tot;// 总结点的数量
struct node
{
int l,r,maxn,sum;
}tree[MAXN];
struct EDGE
{
int u,v,nxt;
}edge[MAXN];
int head[MAXN];
int num=1;
//int nowmax=-1;
int nowsum=0;
void update(int k)
{
tree[k].maxn=max(tree[ls].maxn,tree[rs].maxn);
tree[k].sum=(tree[ls].sum+tree[rs].sum);
}
void add_edge(int x,int y)
{
edge[num].u=x;
edge[num].v=y;
edge[num].nxt=head[x];
head[x]=num++;
}
int dfs1(int now,int nowfa,int nowdeep)
{
deep[now]=nowdeep;
fa[now]=nowfa;
size[now]=1;
for(int i=head[now];i!=-1;i=edge[i].nxt)
{
if(edge[i].v!=nowfa)
{
dfs1(edge[i].v,now,nowdeep+1);
size[now]+=size[edge[i].v];
if(son[now]==-1||size[edge[i].v]>size[son[now]])
son[now]=edge[i].v;
}
}
}
void dfs2(int now,int nowid)
{
tot++;
pos[now]=tot;//更改当前节点的编号
top[now]=nowid;
if(!son[now])// 没有重儿子
return ;
dfs2(son[now],nowid);// 在一条重链上
for(int i=head[now];i!=-1;i=edge[i].nxt)
if(deep[edge[i].v]>deep[edge[i].u]&&edge[i].v!=son[edge[i].u])
dfs2(edge[i].v,edge[i].v);//自己和自己一条重链
return ;
}
void build_tree(int k,int ll,int rr)
{
tree[k].l=ll;tree[k].r=rr;
if(tree[k].l==tree[k].r)
{
tree[k].maxn=tree[k].sum=0;
return ;
}
int mid=(ll+rr)>>1;
build_tree(ls,ll,mid);
build_tree(rs,mid+1,rr);
update(k);
}
void insert(int k,int pos,int val)
{
if(tree[k].l==tree[k].r)
{
tree[k].maxn=tree[k].sum=val;
return ;
}
int mid=(tree[k].l+tree[k].r)>>1;
if(pos<=mid)
insert(ls,pos,val);
if(pos>mid)
insert(rs,pos,val);
update(k); }
int querymax(int k,int ll,int rr)
{
if(ll<=tree[k].l&&tree[k].r<=rr)
return tree[k].maxn;
int mid=(tree[k].l+tree[k].r)>>1,nowmax=-1;
if(ll<=mid)
nowmax=max(nowmax,querymax(ls,ll,rr));
if(rr>mid)
nowmax=max(nowmax,querymax(rs,ll,rr));
return nowmax;
}
int askmax(int u,int v)
{ int ans=-0x7ffff;
while(top[u]!=top[v])//不在一条重链上
{
if(deep[top[u]]<deep[top[v]])
swap(u,v);
ans=max(ans,querymax(1,pos[top[u]],pos[u]));
u=fa[top[u]];
}
if(pos[u]>pos[v])
swap(u,v);
ans=max(ans,querymax(1,pos[u],pos[v]));
return ans;
}
int querysum(int k,int ll,int rr)
{
if(ll<=tree[k].l&&tree[k].r<=rr)
return tree[k].sum;
int mid=(tree[k].l+tree[k].r)>>1,nowsum=0;
if(ll<=mid)
nowsum+=querysum(ls,ll,rr);
if(rr>mid)
nowsum+=querysum(rs,ll,rr);
return nowsum;
}
int asksum(int u,int v)
{
int ans=0;
while(top[u]!=top[v])
{
if(deep[top[u]]<deep[top[v]])
swap(u,v);
ans+=querysum(1,pos[top[u]],pos[u]);
u=fa[top[u]];
}
if(pos[u]>pos[v])
swap(u,v);
ans+=querysum(1,pos[u],pos[v]);
return ans;
}
int main()
{
///freopen("bzoj_1036.in","r",stdin);
//freopen("bzoj_1036.out","w",stdout);
read(n);
memset(head,-1,sizeof(head));
//memset(son,-1,sizeof(son));
for(int i=1;i<=n-1;i++)
{
int x,y;
read(x);read(y);
add_edge(x,y);
add_edge(y,x);
}
for(int i=1;i<=n;i++)
read(a[i]);
dfs1(1,0,0);
dfs2(1,1);
build_tree(1,1,n);
for(int i=1;i<=n;i++)
insert(1,pos[i],a[i]);
int q;
read(q);
for(int i=1;i<=q;i++)
{
string s;
cin>>s;
if(s[1]=='H')// 修改
{
int p,v;
read(p);read(v);
a[p]=v;
insert(1,pos[p],v);
}
else if(s[1]=='M')// 最大值
{
int l,r;
read(l);read(r);
printf("%d\n",askmax(l,r));
}
else//求和
{
int l,r;
read(l);read(r);
printf("%d\n",asksum(l,r));
}
}
return 0;
}

  

P2590 [ZJOI2008]树的统计的更多相关文章

  1. P2590 [ZJOI2008]树的统计(树链剖分)

    P2590 [ZJOI2008]树的统计 虽然是入门树剖模板 但是我终于1A了(大哭) 懒得写啥了(逃 #include<iostream> #include<cstdio> ...

  2. P2590 [ZJOI2008]树的统计(LCT)

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

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

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

  4. Luogu P2590 [ZJOI2008]树的统计

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

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

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

  6. 【luogu P2590 [ZJOI2008]树的统计】 题解

    题目链接:https://www.luogu.org/problemnew/show/P2590 我想学树剖QAQ #include <cstdio> #include <cstri ...

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

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

  8. 洛谷 P2590 [ZJOI2008]树的统计(树链剖分)

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

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

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

随机推荐

  1. Spark基础-scala学习(一、入门)

    Scala解析器的使用 REPL:Read(取值)-> Evaluation(求值)-> Print(打印)->Loop(循环).scala解析器也被称为REPL,会快速编译scal ...

  2. 图片格式PGM缩写

    PGM是Portable Gray Map的缩写.它是灰度图像格式中一种最简单的格式标准.另外两种与之相近的图片格式是PBM和PPM.它们分别相应着黑白图像和彩色图像. PGM的数据存放方式相比于JP ...

  3. 【PHP篇】变量与常量

    变量: 变量的作用域为函数区域 判断是否存在:isset($变量名)://返回bool 判断是否为空:empty($变量名)//变量未声明或者值为空返回1,否则返回false 清除变量:unset($ ...

  4. [干货,阅后进BAT不是梦]面试心得与总结---阿里、小米、腾讯

    之前实习的时候就想着写一篇面经,后来忙就给忘了,现在找完工作了,也是该静下心总结一下走过的路程了,我全盘托出,奉上这篇诚意之作,希望能给未来找工作的人一点指引和总结, 也希望能使大家少走点弯路 , 如 ...

  5. IntelliJ IDEA中用Git插件操作

  6. sql server 性能调优之 资源等待SOS_SCHEDULER_YIELD

    一.概念 SOS_SCHEDULER_YIELD等待类型是一个任务自愿放弃当前的资源占用,让给其他任务使用.   这个等待类型与CPU有直接关系,与内存与也有间接关系,与CPU有关系是因为在sql s ...

  7. .Net程序员学用Oracle系列(19):导出、导入(备份、还原)

    1.传统的导出/导入工具 1.1.EXP 命令详解 1.2.IMP 命令详解 1.3.EXP/IMP 使用技巧 2.新的导出/导入工具 2.1.EXPDP/IMPDP 参数说明 2.2.EXPDP/I ...

  8. MySQL备份mydumper的原理【转】

    本文来自:http://baiyangtx.net/2016/09/04/mydumper-principle/ 相对于MySQL官方提供的逻辑备份工具 mysqldump , mydumper最大的 ...

  9. 小型音乐播放器插件APlayer.js的简单使用例子

      本篇博客将会给出一个小型音乐播放器插件APlayer.js的使用例子.关于APlayer.js的具体介绍和Github地址,可以参考: https://github.com/MoePlayer/A ...

  10. Python爬虫之自制英汉字典

      最近在微信公众号中看到有人用Python做了一个爬虫,可以将输入的英语单词翻译成中文,或者把中文词语翻译成英语单词.笔者看到了,觉得还蛮有意思的,因此,决定自己也写一个玩玩~~   首先我们的爬虫 ...