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本身

Input

输 入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数 q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到 30000之间。

Output

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

Sample Input

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

Sample Output

4
1
2
2
10
6
5
6
5
16

思路

又是从浙江挂下来的考数据结构的歪风邪气。

  树链剖分。不过我们不以边为元素,而以点为元素。由于一个点有可能被访问两次,所以在判重方面有一些麻烦。

大体的思想是每次把点向上提的时候处理提到的节点,但不处理当前的节点。。

恩。。这份代码应该是写的比较差吧,就当复习树链剖分了。

 #include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#include <vector>
#include <ctime>
#include <functional>
#define pritnf printf
#define scafn scanf
#define sacnf scanf
#define For(i,j,k) for(int i=(j);i<=(k);(i)++)
#define Clear(a) memset(a,0,sizeof(a))
using namespace std;
typedef unsigned int Uint;
const int INF=0x3fffffff;
///==============struct declaration============== ///==============var declaration=================
const int MAXN=;
int n,q,tot=,k,v,L,R;
int siz[MAXN],son[MAXN],fa[MAXN],top[MAXN],val[MAXN],No[MAXN],depth[MAXN];
int sum[MAXN*],maxv[MAXN*];
vector <int> Edge[MAXN];
///==============function declaration============
void dfs1(int x);void dfs2(int x);void Init();
void Set_Seg(int o,int l,int r);
void update(int o,int l,int r);
int Query_Max(int o,int l,int r);
int Query_Sum(int o,int l,int r);
///==============main code=======================
int main()
{
#define FILE__
#ifdef FILE__
freopen("input","r",stdin);
freopen("output","w",stdout);
#endif
scanf("%d",&n);
for(int i=;i<n;i++){
int s,e;scanf("%d%d",&s,&e);
Edge[s].push_back(e);Edge[e].push_back(s);
}
for(int i=;i<=n;i++) scanf("%d",val+i);
depth[]=;top[]=;dfs1();dfs2();
for(int i=;i<=n;i++){
v=val[i],k=No[i];
Set_Seg(,,n);
}
scanf("%d",&q);
while (q--){
char cmd[];scanf("%s",cmd);
if (cmd[]=='M'){///QMAX
int _max=-INF;int u,v;
scanf("%d%d",&u,&v);if (u==v) _max=val[u];
_max=max(_max,val[u]);
_max=max(_max,val[v]);///if the point locates at a top of a Heavy String
while (u!=v){
if (depth[top[u]]<depth[top[v]]) swap(u,v);///Make u is always deeper
if (top[u]==top[v]){///Locate at the same Heavy String
L=No[u],R=No[v];if (L>R) swap(L,R);L++;R--;
if (L<=R)
_max=max(_max,Query_Max(,,n));
break;
}
if (top[u]==u){///Top of a heavy string
u=fa[u];
_max=max(_max,val[u]);
}
else{///middle of a heavy string
L=No[top[u]],R=No[u];if (L>R) swap(L,R);R--;
_max=max(_max,Query_Max(,,n));u=top[u];
}
}
printf("%d\n",_max);
}
else if (cmd[]=='S'){///QSUM
int _sum=;int u,v;
scanf("%d%d",&u,&v);
_sum+=val[u];
if (u!=v) _sum+=val[v];///if the point locates at a top of a Heavy String
while (u!=v){
if (depth[top[u]]<depth[top[v]]) swap(u,v);///Make u is always deeper
if (top[u]==top[v]){///Locate at the same Heavy String
L=No[v],R=No[u];if (L>R) swap(L,R);L++;R--;
if (L<=R)
_sum+=Query_Sum(,,n);
break;
}
if (top[u]==u){///Top of a heavy string
u=fa[u];
if (u!=v)
_sum+=val[u];
}
else{///middle of a heavy string
L=No[top[u]],R=No[u];if (L>R) swap(L,R);R--;
_sum+=Query_Sum(,,n);u=top[u];
}
}
printf("%d\n",_sum);
}
else if (cmd[]=='H'){///Change
scanf("%d%d",&k,&v);val[k]=v;k=No[k];
Set_Seg(,,n);
}
}
return ;
}
///================fuction code====================
void dfs1(int x){
siz[x]=;son[x]=-;
for(int i=;i<Edge[x].size();i++){
int &e=Edge[x][i];
if (fa[x]==e) continue;
fa[e]=x;depth[e]=depth[x]+;dfs1(e);
siz[x]+=siz[e];
if (son[x]==-||siz[son[x]]<siz[e])
son[x]=e;
}
}
void dfs2(int x){
No[x]=++tot;
if (siz[x]!=) {
top[son[x]]=top[x];
dfs2(son[x]);
}
for(int i=;i<Edge[x].size();i++){
int &e=Edge[x][i];
if (son[x]==e||fa[x]==e) continue;
top[e]=e;dfs2(e);
}
}
void Set_Seg(int o,int l,int r){
int m=(l+r)>>,lc=o*,rc=o*+;
if (l==r){
sum[o]=maxv[o]=v;
return;
}
if (m>=k) Set_Seg(lc,l,m);
else Set_Seg(rc,m+,r);
update(o,l,r);
}
void update(int o,int l,int r){
int lc=o*,rc=o*+;
sum[o]=sum[lc]+sum[rc];
maxv[o]=max(maxv[lc],maxv[rc]);
}
int Query_Max(int o,int l,int r){
if (L<=l&&r<=R)
return maxv[o];
int m=(l+r)>>,lc=o*,rc=o*+;
int Left=-INF,Right=-INF;
if (m>=L) Left=Query_Max(lc,l,m);
if (m<R) Right=Query_Max(rc,m+,r);
return max(Left,Right);
}
int Query_Sum(int o,int l,int r){
if (L<=l&&r<=R)
return sum[o];
int m=(l+r)>>,lc=o*,rc=o*+;
int Left=,Right=;
if (m>=L) Left=Query_Sum(lc,l,m);
if (m<R) Right=Query_Sum(rc,m+,r);
return Left+Right;
}

BZOJ 1036

【ZJOI2008】 树的统计 count的更多相关文章

  1. BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]【学习笔记】

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

  2. bzoj1036 [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 12646  Solved: 5085 [Subm ...

  3. BZOJ 1036: [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 14354  Solved: 5802 [Subm ...

  4. 【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分

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

  5. bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

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

  6. Bzoj 1036: [ZJOI2008]树的统计Count 树链剖分,LCT

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

  7. 数据结构(LCT动态树):BZOJ 1036: [ZJOI2008]树的统计Count

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

  8. BZOJ 1036: [ZJOI2008]树的统计Count( 树链剖分 )

    树链剖分... 不知道为什么跑这么慢 = = 调了一节课啊跪.. ------------------------------------------------------------------- ...

  9. 1036: [ZJOI2008]树的统计Count

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

  10. bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题

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

随机推荐

  1. python基础之编码问题

    python基础之编码问题 本节内容 字符串编码问题由来 字符串编码解决方案 1.字符串编码问题由来 由于字符串编码是从ascii--->unicode--->utf-8(utf-16和u ...

  2. Linux网卡配置及学习linux的注意事项

    一.网卡配置 1.ifconfig网卡信息,配置IP ifconfig eth0 192.168.2.102 2.修改网卡配置(连接不了可能是IP给占用了) 进入编辑界面命令:vi /etc/sysc ...

  3. sql 首写字母查询姓名(字段)

    来自网上大神,不知道是谁,挂不上链接 /////////////////////// 1.生成方法函数 create function f_GetPy(@str nvarchar(4000)) ret ...

  4. JavaScript模板引擎artTemplate.js——template()方法

    template(id, data)方法: id:必传,渲染模板的id. data:可选,一个Object对象. return:传data—>渲染完成html代码:不传data—>一个渲染 ...

  5. 83 parrted-分区和分区大小的调整

    parted命令是由GNU组织开发的一款功能强大的磁盘分区和分区大小调整工具,与fdisk不同,它支持调整分区的大小.作为一种设计用于Linux的工具,它没有构建成处理与fdisk关联的多种分区类型, ...

  6. linux运维工作职责

     (1)运维人员要谨记的6个字:运维人员做事需遵循:简单.易用.高效(2)运维人员服务的3大宗旨:1.企业数据安全保障.2.7*24小时业务持续提供服务.3.不断提升用户感受.体验.(3)初中级运维的 ...

  7. C#接口和抽象类的区别

    大家都容易把这两者搞混,我也一样,在听李建忠老师的设计模式时,他也老把抽象类说成接口,弄的我就更糊涂了,所以找了些网上的资料.      一.抽象类:      抽象类是特殊的类,只是不能被实例化:除 ...

  8. hihoCoder 后缀数组 重复旋律

    #1403 : 后缀数组一·重复旋律 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成 ...

  9. css-css权威指南学习笔记4

    第三章 1.继承的值没有特殊性,甚至连0的特殊性都没有.所以改变超链接的样式一般需要独立声明,无法通过继承改变. 2.层叠--冲突的声明通过这个层叠的过程排序,并由此确定最终的文档表示.这个过程的核心 ...

  10. linux之svn

    sudo apt-get install subversion 实践出真理