树的统计Count---树链剖分
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
很好的树链剖分模板:
#include<iostream>
#include<cstdio>
#include<cstring>
#define inf 0x7fffffff
#define N 30005
#define M 60005
using namespace std;
int n,q,cnt,sz;
int fa[N][],v[N],deep[N],size[N],head[N];
int pos[N],belong[N];
bool vis[N];
struct data
{
int to,next;
} e[M];
struct seg
{
int l,r,mx,sum;
} t[];
void insert(int u,int v)
{
e[++cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
e[++cnt].to=u;
e[cnt].next=head[v];
head[v]=cnt;
}
void init()
{
scanf("%d",&n);
for(int i=; i<n; i++)
{
int x,y;
scanf("%d%d",&x,&y);
insert(x,y);
}
for(int i=; i<=n; i++)
scanf("%d",&v[i]);
}
void dfs1(int x)
{
size[x]=;
vis[x]=;
for(int i=; i<=; i++)
{
if(deep[x]<(<<i))break;
fa[x][i]=fa[fa[x][i-]][i-];//倍增处理祖先信息
}
for(int i=head[x]; i; i=e[i].next)
{
if(vis[e[i].to])continue;
deep[e[i].to]=deep[x]+;
fa[e[i].to][]=x;
dfs1(e[i].to);
size[x]+=size[e[i].to];
}
}
void dfs2(int x,int chain)
{
int k=;
sz++;
pos[x]=sz;//分配x结点在线段树中的编号
belong[x]=chain;
for(int i=head[x]; i; i=e[i].next)
if(deep[e[i].to]>deep[x]&&size[e[i].to]>size[k])
k=e[i].to;//选择子树最大的儿子继承重链
if(k==)return;
dfs2(k,chain);
for(int i=head[x]; i; i=e[i].next)
if(deep[e[i].to]>deep[x]&&k!=e[i].to)
dfs2(e[i].to,e[i].to);//其余儿子新开重链
}
int lca(int x,int y)//求lca
{
if(deep[x]<deep[y])swap(x,y);
int t=deep[x]-deep[y];
for(int i=; i<=; i++)
if(t&(<<i))x=fa[x][i];
for(int i=; i>=; i--)
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
if(x==y)return x;
else return fa[x][];
}
void build(int k,int l,int r)//建线段树
{
t[k].l=l;
t[k].r=r;
if(l==r)return;
int mid=(l+r)>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
}
void change(int k,int x,int y)//线段树单点修改
{
int l=t[k].l,r=t[k].r,mid=(l+r)>>;
if(l==r)
{
t[k].sum=t[k].mx=y;
return;
}
if(x<=mid)change(k<<,x,y);
else change(k<<|,x,y);
t[k].sum=t[k<<].sum+t[k<<|].sum;
t[k].mx=max(t[k<<].mx,t[k<<|].mx);
}
int querysum(int k,int x,int y)//线段树区间求和
{
int l=t[k].l,r=t[k].r,mid=(l+r)>>;
if(l==x&&y==r)return t[k].sum;
if(y<=mid)return querysum(k<<,x,y);
else if(x>mid)return querysum(k<<|,x,y);
else
{
return querysum(k<<,x,mid)+querysum(k<<|,mid+,y);
}
}
int querymx(int k,int x,int y)//线段树区间求最大值
{
int l=t[k].l,r=t[k].r,mid=(l+r)>>;
if(l==x&&y==r)return t[k].mx;
if(y<=mid)return querymx(k<<,x,y);
else if(x>mid)return querymx(k<<|,x,y);
else
{
return max(querymx(k<<,x,mid),querymx(k<<|,mid+,y));
}
}
int solvesum(int x,int f)
{
int sum=;
while(belong[x]!=belong[f])//不在一条重链上就将x跳到链首,走一条轻边,如此反复
{
sum+=querysum(,pos[belong[x]],pos[x]);
x=fa[belong[x]][];
}
sum+=querysum(,pos[f],pos[x]);
return sum;
}
int solvemx(int x,int f)
{
int mx=-inf;
while(belong[x]!=belong[f])
{
mx=max(mx,querymx(,pos[belong[x]],pos[x]));
x=fa[belong[x]][];
}
mx=max(mx,querymx(,pos[f],pos[x]));
return mx;
}
void solve()
{
build(,,n);
for(int i=; i<=n; i++)
change(,pos[i],v[i]);
scanf("%d",&q);
char ch[];
for(int i=; i<=q; i++)
{
int x,y;
scanf("%s%d%d",ch,&x,&y);
if(ch[]=='C')
{
v[x]=y;
change(,pos[x],y);
}
else
{
int t=lca(x,y);
if(ch[]=='M')
printf("%d\n",max(solvemx(x,t),solvemx(y,t)));
else
printf("%d\n",solvesum(x,t)+solvesum(y,t)-v[t]);
}
}
}
int main()
{
init();
dfs1();
dfs2(,);
solve();
return ;
}
树的统计Count---树链剖分的更多相关文章
- BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]【学习笔记】
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 14302 Solved: 5779[Submit ...
- 【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分
[BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. ...
- Bzoj 1036: [ZJOI2008]树的统计Count 树链剖分,LCT
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 11102 Solved: 4490[Submit ...
- BZOJ 1036: [ZJOI2008]树的统计Count( 树链剖分 )
树链剖分... 不知道为什么跑这么慢 = = 调了一节课啊跪.. ------------------------------------------------------------------- ...
- bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题
[ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u ...
- bzoj 1036: [ZJOI2008]树的统计Count 树链剖分+线段树
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 16294 Solved: 6645[Submit ...
- BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 14982 Solved: 6081[Submit ...
- BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分)(线段树单点修改)
[ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 14968 Solved: 6079[Submit][Stat ...
- Cogs 1688. [ZJOI2008]树的统计Count(树链剖分+线段树||LCT)
[ZJOI2008]树的统计Count ★★★ 输入文件:bzoj_1036.in 输出文件:bzoj_1036.out 简单对比 时间限制:5 s 内存限制:162 MB [题目描述] 一棵树上有n ...
- BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时 ...
随机推荐
- 算法 - 求两个自然数的最小公倍数(C++)
//************************************************************************************************** ...
- 配置ST3在浏览器中打开
打开Preferences - 「Key Bindings - User」,添加此行: {"keys": ["f1"],"command": ...
- C++中实现回调机制的几种方式[转]
(1)Callback方式Callback的本质是设置一个函数指针进去,然后在需要需要触发某个事件时调用该方法, 比如Windows的窗口消息处理函数就是这种类型. 比如下面的示例代码,我们在Do ...
- 自己做的加速app测试流程的小工具,目前打算开放使用,想注册的朋友抓紧了,嘻嘻
为了加速小团队app的测试流程做了这个东西,www.xunce.net 主要特性: web: 一键上传app,方便随时下载 备注测试要点 添加附件,如checklist等文档 自动识别app版本,名 ...
- spring中bean配置和bean注入
1 bean与spring容器的关系 Bean配置信息定义了Bean的实现及依赖关系,Spring容器根据各种形式的Bean配置信息在容器内部建立Bean定义注册表,然后根据注册表加载.实例化Bean ...
- 读书笔记_Effective_C++_条款四十八:了解模板元编程
作为模板部分的结束节,本条款谈到了模板元编程,元编程本质上就是将运行期的代价转移到编译期,它利用template编译生成C++源码,举下面阶乘例子: template <int N> st ...
- 利用SSIS发送邮件
璎Nicole珞 博客园 闪存 首页 新随笔 联系 管理 订阅 随笔- 15 文章- 0 评论- 0 SSIS 利用发送邮件服务 Send Email Task 1. 在SSIS中如何发送邮 ...
- Three.js源码阅读笔记-5
Core::Ray 该类用来表示空间中的“射线”,主要用来进行碰撞检测. THREE.Ray = function ( origin, direction ) { this.origin = ( or ...
- ROC和AUC介绍以及如何计算AUC ---好!!!!
from:https://www.douban.com/note/284051363/?type=like 原帖发表在我的博客:http://alexkong.net/2013/06/introduc ...
- Caching查看窗口
闲来无事,做了一个简约的Caching查看窗口,可以方便的查看本地缓存的使用情况: 下面的URL和VersionNum用来查看某个特定资源的特定版本是否存在,分别输入所需信息,点击“检测”,即可在下面 ...