这道题很久以前用树链剖分写的,最近在学LCT ,就用LCT再写了一遍,也有一些收获。

因为这道题点权可以是负数,所以在update时就要注意一下,因为平时我的0节点表示空,它的点权为0,这样可以处理点权为非负求最大值和求和的情况(即不用特判某个点是否有左右儿子,直接更新就行了),但这道题就不行(求和要求它为0,求最大值要求它为-oo)。所以就必须特判~~~~

综上:若0号节点存在一个不可能成为答案(在求最大值时是-oo,求最小值时是+oo)或对答案没有贡献的值(在求和时是0)时,初始化时将0节点的权值设为该值,更新时就可以不用特判某个点是否为0。否则引用左右儿子值时就必须特判某个节点是否有左右儿子。

LCT用的时间大概是树链剖分的两倍。

树链剖分:

 /**************************************************************
Problem: 1036
User: idy002
Language: C++
Result: Accepted
Time:2880 ms
Memory:5116 kb
****************************************************************/ #include <cstdio>
#include <vector>
#define lson rt<<1
#define rson rt<<1|1
#define inf 300000000
#define maxn 30001
using namespace std; int n;
vector<int> g[maxn];
int wght[maxn], siz[maxn], son[maxn], pre[maxn], dep[maxn], top[maxn], vid[maxn], vcnt;
int smax[maxn<<], ssum[maxn<<]; void up_sum( int pos, int v, int rt, int l, int r ) {
if( l==r ) {
ssum[rt] = v;
return;
}
int mid=(l+r)>>;
if( mid>=pos ) up_sum( pos, v, lson, l, mid );
else up_sum( pos, v, rson, mid+, r );
ssum[rt] = ssum[lson] + ssum[rson];
}
void up_max( int pos, int v, int rt, int l, int r ) {
if( l==r ) {
smax[rt] = v;
return;
}
int mid=(l+r)>>;
if( mid>=pos ) up_max( pos, v, lson, l, mid );
else up_max( pos, v, rson, mid+, r );
smax[rt] = max( smax[lson], smax[rson] );
}
int qu_sum( int L, int R, int rt, int l, int r ) {
if( L<=l && r<=R ) return ssum[rt];
int mid=(l+r)>>, re=;
if( mid>=L ) re+=qu_sum(L,R,lson,l,mid);
if( mid+<=R ) re+=qu_sum(L,R,rson,mid+,r);
return re;
}
int qu_max( int L, int R, int rt, int l, int r ) {
if( L<=l && r<=R ) return smax[rt];
int mid=(l+r)>>, re=-inf;
if( mid>=L ) re = qu_max( L,R,lson,l,mid);
if( mid+<=R ) re = max( re, qu_max( L,R,rson,mid+,r ) );
return re;
}
void dfs1( int u ) {
siz[u] = , son[u] = ;
for( int t=; t<(int)g[u].size(); t++ ) {
int v=g[u][t];
if( v==pre[u] ) continue;
pre[v] = u;
dep[v] = dep[u]+;
dfs1(v);
siz[u] += siz[v];
son[u] = siz[v]>siz[son[u]] ? v : son[u];
}
}
void dfs2( int u, int tp ) {
vid[u] = ++vcnt, top[u] = tp;
if( son[u] ) dfs2(son[u],tp);
for( int t=; t<(int)g[u].size(); t++ ) {
int v=g[u][t];
if( v==pre[u] || v==son[u] ) continue;
dfs2(v,v);
}
}
void build() {
pre[] = , dep[] = ;
dfs1();
vcnt = ;
dfs2(,);
for( int i=; i<=n; i++ ) {
up_sum( vid[i], wght[i], , , vcnt );
up_max( vid[i], wght[i], , , vcnt );
}
}
void update( int v, int val ) {
up_sum( vid[v], val, , , vcnt );
up_max( vid[v], val, , , vcnt );
}
int query_sum( int u, int v ) {
int r=;
while( top[u]!=top[v] ) {
if( dep[top[u]]<dep[top[v]] ) swap(u,v);
r += qu_sum( vid[top[u]], vid[u], , , vcnt );
u = pre[top[u]];
}
if( u==v ) return r+qu_sum(vid[u],vid[v],,,vcnt);
if( dep[u]<dep[v] ) swap(u,v);
r += qu_sum( vid[v], vid[u], , , vcnt );
return r;
}
int query_max( int u, int v ) {
int r=-inf;
while( top[u]!=top[v] ) {
if( dep[top[u]]<dep[top[v]] ) swap(u,v);
r = max( r, qu_max( vid[top[u]], vid[u], , , vcnt ) );
u = pre[top[u]];
}
if( u==v ) return max( r, qu_max( vid[u], vid[v], , , vcnt ) );
if( dep[u]<dep[v] ) swap(u,v);
r = max( r, qu_max( vid[v], vid[u], , , vcnt ) );
return r;
}
void answer() {
int q, a, b;
scanf( "%d", &q );
while(q--) {
char dir[];
scanf( "%s%d%d", dir, &a, &b );
if( dir[]=='C' )
update(a,b);
else if( dir[]=='S' )
printf( "%d\n", query_sum(a,b) );
else
printf( "%d\n", query_max(a,b) );
}
}
void input() {
scanf( "%d", &n );
for( int i=,u,v; i<n; i++ ) {
scanf( "%d%d", &u, &v );
g[u].push_back(v);
g[v].push_back(u);
}
for( int i=; i<=n; i++ )
scanf( "%d", wght+i );
}
int main() {
input();
build();
answer();
}

LCT:

 /**************************************************************
Problem: 1036
User: idy002
Language: C++
Result: Accepted
Time:5816 ms
Memory:2932 kb
****************************************************************/ #include <cstdio>
#include <iostream>
#define maxn 30010
#define oo 0x3f3f3f3f
using namespace std; namespace L {
int pnt[maxn], pre[maxn], son[maxn][], val[maxn], mxv[maxn], sum[maxn], rtg[maxn]; void update( int u ) {
mxv[u] = sum[u] = val[u];
int ls = son[u][], rs = son[u][];
if(ls) {
mxv[u] = max( mxv[u], mxv[ls] );
sum[u] += sum[ls];
}
if(rs) {
mxv[u] = max( mxv[u], mxv[rs] );
sum[u] += sum[rs];
}
}
void rotate( int u, int d ) {
int p = pre[u];
int s = son[u][!d];
int ss = son[s][d];
son[u][!d] = ss;
son[s][d] = u;
if( p ) son[p][ u==son[p][] ] = s;
else pnt[s] = pnt[u];
pre[u] = s;
pre[ss] = u;
pre[s] = p;
update( u );
update( s );
}
void pushdown( int u ) {
if( rtg[u] ) {
int &ls = son[u][], &rs = son[u][];
swap( ls, rs );
rtg[ls] ^= ;
rtg[rs] ^= ;
rtg[u] = ;
}
}
void big_push( int u ) {
if( pre[u] ) big_push(pre[u]);
pushdown( u );
}
void splay( int u, int top= ) {
big_push( u );
while( pre[u]!=top ) {
int p = pre[u];
int nl = u==son[p][];
if( pre[p]==top ) {
rotate( p, nl );
} else {
int pp = pre[p];
int pl = p==son[pp][];
if( nl==pl ) {
rotate( pp, pl );
rotate( p, nl );
} else {
rotate( p, nl );
rotate( pp, pl );
}
}
}
}
void access( int nd ) {
int u = nd;
int v = ;
while( u ) {
splay( u );
int s = son[u][];
pre[s] = ;
pnt[s] = u;
pre[v] = u;
son[u][] = v;
update(u);
v = u;
u = pnt[u];
}
splay( nd );
}
int findroot( int u ) {
while( pre[u] ) u = pre[u];
while( pnt[u] ) {
u = pnt[u];
while( pre[u] ) u = pre[u];
}
return u;
}
void makeroot( int u ) {
access( u );
rtg[u] ^= ;
}
void link( int u, int v ) {
makeroot( u );
makeroot( v );
pnt[u] = v;
}
void up_val( int u, int w ) {
splay( u );
val[u] = w;
update( u );
}
int qu_max( int u, int v ) {
makeroot( u );
access( v );
if( son[v][] ) return max( val[v], mxv[son[v][]] );
else return val[v];
}
int qu_sum( int u, int v ) {
makeroot( u );
access( v );
if( son[v][] ) return val[v] + sum[son[v][]];
else return val[v];
}
}; int n, q; int main() {
scanf( "%d", &n );
for( int i=,u,v; i<=n; i++ ) {
scanf( "%d%d", &u, &v );
L::link(u,v);
}
for( int i=,w; i<=n; i++ ) {
scanf( "%d", &w );
L::up_val(i,w);
}
scanf( "%d", &q );
while( q-- ) {
char ch[];
int u, v, w;
scanf( "%s", ch );
if( ch[]=='C' ) {
scanf( "%d%d", &u, &w );
L::up_val( u, w );
} else if( ch[]=='M' ) {
scanf( "%d%d", &u, &v );
printf( "%d\n", L::qu_max( u, v ) );
} else {
scanf( "%d%d", &u, &v );
printf( "%d\n", L::qu_sum( u, v ) );
}
}
}

bzoj1036 count 树链剖分或LCT的更多相关文章

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

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

  2. 【BZOJ1036】树的统计Count(树链剖分,LCT)

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

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

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

  4. Cogs 1688. [ZJOI2008]树的统计Count(树链剖分+线段树||LCT)

    [ZJOI2008]树的统计Count ★★★ 输入文件:bzoj_1036.in 输出文件:bzoj_1036.out 简单对比 时间限制:5 s 内存限制:162 MB [题目描述] 一棵树上有n ...

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

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

  6. BZOJ1036 [ZJOI2008]树的统计Count 树链剖分

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1036 题意概括 一个树,每个节点有一个权值.3种操作. 1:修改某一个节点的权值. 2:询问某两个 ...

  7. 【bzoj1036】[ZJOI2008]树的统计Count 树链剖分+线段树

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

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

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

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

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

随机推荐

  1. Go Web 编程 第一章 Web相关概念

    第一章 Go与Web应用 Go学习群:415660935 1.1 Web应用 在计算机的世界里,应用(application)是一个与用户进行交互,并完成用户特定任务的软件程序.而Web应用则是部署在 ...

  2. uboot1.1.6 start.s分析

    .Stage1 start.S代码结构 u-boot的stage1代码通常放在start.S文件中,他用汇编语言写成,其主要代码部分如下:(1)定义入口.由于一个可执行的Image必须有一个入口点,并 ...

  3. SVM问题再理解与分析——我的角度

    SVM问题再理解与分析--我的角度 欢迎关注我的博客:http://www.cnblogs.com/xujianqing/ 支持向量机问题 问题先按照几何间隔最大化的原则引出他的问题为 上面的约束条件 ...

  4. 用VIM查看编辑二进制文件

    用VIM查看编辑二进制文件 vim可以很方便地编辑二进制文件,个人认为它比emacs的二进制编辑方式更好用.vim中二进制文件的编辑是先通过外部程序xxd来把文件dump成其二进制的文本形式,然后就可 ...

  5. python3.4.3安装allure2记录

    一.安装:cmd执行命令pip install allure-pytest 二.下载allure2:2.7.0版本 https://dl.bintray.com/qameta/generic/io/q ...

  6. 谁说运维用ELK没用?我就说很有用,只是你之前不会用【转】

    1.安装JDK 1)登陆ORACLE官网 (http://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html ...

  7. C#技术分享【PDF转换成图片——11种方案】

    1.[iTextSharp.dll],C# 开源PDF处理工具,可以任意操作PDF,并可以提取PDF中的文字和图片,但不能直接将PDF转换成图片. DLL和源码 下载地址:http://downloa ...

  8. 190.Reverse Bits---位运算

    题目链接:https://leetcode.com/problems/reverse-bits/description/ 题目大意:将数值的二进制反转. 法一(借鉴):由于是无符号32位整型,当二进制 ...

  9. 【题解】BZOJ 3600: 没有人的算术——替罪羊树、线段树

    题目传送门 题意 具体的自己去上面看吧...反正不是权限题. 简单来说,就是定义了一类新的数,每个数是0或者为 \((x_L, x_R)\) ,同时定义比较大小的方式为:非零数大于零,否则按字典序比较 ...

  10. iscsi服务器的搭建

    1.在您的存储服务器上,以 root 用户身份使用 yum 命令安装 scsi-t arget -ut ils 软件包. # yum install -y scsi-target-utils 2.把您 ...