描述


http://www.lydsy.com/JudgeOnline/problem.php?id=1036

给出一棵树以及各点的权值,对数进行如下三种操作:

1.改变某一节点u的值为t;

2.求节点u到节点v之间(包括u与v)的最大值;

3.求节点u到节点v之间(包括u与v)的和.

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 12002  Solved: 4864
[Submit][Status][Discuss]

Description

  一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. 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

HINT

Source

分析


树链剖分模板题,但貌似LCA写得太原始了= =,并不会其他方法.直接裸的原始LCA好像可以过两个点...

注意:

1.对u,v进行操作时是判断tib[u]与tib[v]的大小,不然上线段树会炸.(tib[top[u]]<=tib[u]恒成立)

2.在LCA时别少写了dep[top[u]]==dep[top[v]]的情况.

 #include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#define read(a) a=getnum()
#define lson (2*k)
#define rson (2*k+1)
#define mid ((a[k].l+a[k].r)>>1) using namespace std; const int maxn=+,INF=+; struct node
{
int l,r,k,x,m;
}; int n,q;
int label;
int w[maxn];
int fa[maxn];
int dep[maxn];
int size[maxn];
int son[maxn];
int top[maxn];
int tib[maxn];
int rev_tib[maxn];
bool vis1[maxn];
bool vis2[maxn];
vector <int> g1[maxn];
vector <int> g2[maxn];
node a[*maxn]; inline int getnum()
{
int r=,k=;
char c;
for(c=getchar();c<''||c>'';c=getchar()) if(c=='-') k=-;
for(;c>=''&&c<='';c=getchar()) r=r*+c-'';
return r*k;
} void build_tree(int l,int r,int k)
{
a[k].l=l; a[k].r=r;
if(l==r)
{
a[k].x=a[k].m=w[rev_tib[l]];
return;
}
build_tree(l,mid,lson);
build_tree(mid+,r,rson);
a[k].x=a[lson].x+a[rson].x;
a[k].m=max(a[lson].m,a[rson].m);
} void update(int x,int t,int k)
{
if(a[k].l==a[k].r&&a[k].l==x)
{
a[k].x=a[k].m=t;
return;
}
if(x<=mid) update(x,t,lson);
else update(x,t,rson);
a[k].x=a[lson].x+a[rson].x;
a[k].m=max(a[lson].m,a[rson].m);
} int get_max(int l,int r,int k)
{
if(l==a[k].l&&r==a[k].r)
{
return a[k].m;
}
if(r<=mid) return get_max(l,r,lson);
else if(l>mid) return get_max(l,r,rson);
else return max(get_max(l,mid,lson),get_max(mid+,r,rson));
} int get_sum(int l,int r,int k)
{
if(l==a[k].l&&r==a[k].r)
{
return a[k].x;
}
if(r<=mid) return get_sum(l,r,lson);
else if(l>mid) return get_sum(l,r,rson);
else return get_sum(l,mid,lson)+get_sum(mid+,r,rson);
} void find_h_e(int u,int father,int depth)
{
vis1[u]=true;
fa[u]=father;
dep[u]=depth;
size[u]=;
son[u]=;
int max_size=;
for(int i=;i<g1[u].size();i++)
{
int v=g1[u][i];
if(vis1[v]) continue;
g2[u].push_back(v);
find_h_e(v,u,depth+);
size[u]+=size[v];
if(size[v]>max_size)
{
max_size=size[v];
son[u]=v;
}
}
} void conect_h_e(int u,int ancestor)
{
vis2[u]=true;
top[u]=ancestor;
tib[u]=++label;
rev_tib[label]=u;
if(son[u])
{
conect_h_e(son[u],ancestor);
}
for(int i=;i<g2[u].size();i++)
{
int v=g2[u][i];
if(vis2[v]) continue;
conect_h_e(v,v);
}
} void Change(int u,int t)
{
update(tib[u],t,);
} int Q_max(int u,int v)
{
int max_now=-INF;
while(top[u]!=top[v])
{
if(dep[top[u]]==dep[top[v]])
{
max_now=max(max_now,get_max(tib[top[u]],tib[u],));
u=fa[top[u]];
continue;
}
while(dep[top[u]]>dep[top[v]])
{
max_now=max(max_now,get_max(tib[top[u]],tib[u],));
u=fa[top[u]];
}
while(dep[top[u]]<dep[top[v]])
{
max_now=max(max_now,get_max(tib[top[v]],tib[v],));
v=fa[top[v]];
}
}
max_now=max(max_now,get_max(min(tib[v],tib[u]),max(tib[u],tib[v]),));
return max_now;
} int Q_sum(int u,int v)
{
int sum_now=;
while(top[u]!=top[v])
{
if(dep[top[u]]==dep[top[v]])
{
sum_now+=get_sum(tib[top[u]],tib[u],);
u=fa[top[u]];
continue;
}
while(dep[top[u]]>dep[top[v]])
{
sum_now+=get_sum(tib[top[u]],tib[u],);
u=fa[top[u]];
}
while(dep[top[u]]<dep[top[v]])
{
sum_now+=get_sum(tib[top[v]],tib[v],);
v=fa[top[v]];
}
}
sum_now+=get_sum(min(tib[v],tib[u]),max(tib[u],tib[v]),);
return sum_now;
} void init()
{
read(n);
for(int i=;i<n;i++)
{
int u,v;
read(u); read(v);
g1[u].push_back(v);
g1[v].push_back(u);
}
for(int i=;i<=n;i++)
{
read(w[i]);
}
} int main()
{
init();
read(q);
find_h_e(,,);
conect_h_e(,);
build_tree(,n,);
for(int i=;i<=q;i++)
{
char c;
c=getchar();
if(c=='C')
{
int u,t;
read(u); read(t);
Change(u,t);
}
else
{
c=getchar();
if(c=='M')
{
int u,v;
read(u); read(v);
printf("%d\n",Q_max(u,v));
}
else
{
int u,v;
read(u); read(v);
printf("%d\n",Q_sum(u,v));
}
}
}
return ;
}

BZOJ_1036_[ZJOI2008]_树的统计Conut_(树链剖分)的更多相关文章

  1. (持续更新)虚树,KD-Tree,长链剖分,后缀数组,后缀自动机

    真的就是讲课两天,吸收一个月呢! \(1.\)虚树 \(2.\)KD-Tree \(3.\)长链剖分 \(4.\)后缀数组 后缀数组 \(5.\)后缀自动机 后缀自动机

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

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

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

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

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

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

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

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

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

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

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

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

  8. bzoj 1036: [ZJOI2008]树的统计Count 树链剖分+线段树

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

  9. BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)

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

随机推荐

  1. KP 佛学禅语

    1.人之所以痛苦,在于追求错误的东西. 2.如果你不给自己烦恼,别人也永远不可能给你烦恼.因为你自己的内心,你放不下. 3.你永远要感谢给你逆境的众生. 4.你永远要宽恕众生,不论他有多坏,甚至他伤害 ...

  2. HTTP协议认识

    一.HTTP协议概念 HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议 HTTP是一个应用层协议,由请求和响应 ...

  3. 利用switch语句计算特定的年份的月份共有几天。

    //利用switch语句计算特定的年份的月份共有几天. let year =2015 let month =2 //先判断闰年中二月份的情况 ifmonth ==2 { if (year %400 = ...

  4. C#基础总复习03

    继续更新...接下来就是面向对象的知识了 1.面向对象:概念:使用面向对象的思想进行编程可以让的程序变得扩展性更高,便于维护: 我们在现实生活中去描述一个人的时候,通过描述这个人的特征和行为. 我们在 ...

  5. CustomEditor的文件要放在Assets/Editor目录下

    using UnityEditor; using UnityEngine; [CustomEditor(typeof(test))] public class testEditor : Editor ...

  6. (转)Xcode 中设置部分文件ARC支持

    ARC是什么 ARC是iOS 5推出的新功能,全称叫 ARC(Automatic Reference Counting).简单地说,就是代码中自动加入了retain/release,原先需要手动添加的 ...

  7. sublime2 Ctags 快捷键

    Commands Listing Command Key Binding Alt Binding Mouse Binding rebuild_ctags ctrl+t, ctrl+r     navi ...

  8. sass中常用mixin

    //设置字体大小 @mixin font($s:14px,$h:1.5,$f:microsoft yahei){ font:$s/#{$h} $f; } //参数(方向,大小,颜色),默认:向下,10 ...

  9. linux 文件操作编程

    Linux中所有的设备和文件的操作都使用文件描述符来进行. 文件描述符是一个非负的整数,它是一个索引值,指向内核中每个进程打开的记录表. 当打开一个文件或者创建一个新文件时,内核就向进程返回一个文件描 ...

  10. ubuntu下php开发环境搭建,nginx+(cgi)php5fpm+memcached+xdebug

    由于只是开发环境,所以都是选择比较简单的apt-get安装方式 ,但中间也遇到一点问题. 首先安装nginx nginx的安装和配置其实很简单,nginx本身非常轻量级, 直接 sudo apt-ge ...