数的统计count(bzoj1036)
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
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
1
2
2
10
6
5
6
5
16
/*
第一次写树链剖分,大概就是把一棵树分成很多链,然后把这些链首尾相接,形成一个序列,然后再用其他数据结构维护这个序列。
具体操作是把边分为轻边和重边,重边是某个节点与他的最大字数的根节点的连边,由重边构成的链叫重链。
先说一下几个数组的意思:
size[]数组,用来保存以x为根的子树节点个数
top[]数组,用来保存当前节点的所在链的顶端节点
son[]数组,用来保存重儿子
dep[]数组,用来保存当前节点的深度
fa[]数组,用来保存当前节点的父亲
pos[]数组,用来保存树中每个节点剖分后的新编号
第一遍dfs:求出树每个结点的深度dep[x],其为根的子树大小size[x]
第二遍dfs:根节点为起点,向下拓展构建重链
选择最大的一个子树的根继承当前重链
其余节点,都以该节点为起点向下重新拉一条重链
给每个结点分配一个位置编号,每条重链就相当于一段区间,用数据结构去维护。
把所有的重链首尾相接,放到同一个数据结构上,然后维护这一个整体即可 修改操作
1、单独修改一个点的权值
根据其编号直接在数据结构中修改就行了。
2、修改点u和点v的路径上的权值
(1)若u和v在同一条重链上
直接用数据结构修改pos[u]至pos[v]间的值。
(2)若u和v不在同一条重链上
一边进行修改,一边将u和v往同一条重链上靠,然后就变成了情况(1)。 查询操作
查询操作的分析过程同修改操作
*/
#include<cstdio>
#include<iostream>
#define N 300010
#define inf 1000000000
#define lson l,mid,now*2
#define rson mid+1,r,now*2+1
using namespace std;
int pos[N],son[N],top[N],dep[N],size[N],fa[N];
int head[N],v[N],n,m,sum[N*],mx[N*],sz;
struct node{
int to,pre;
};node e[N*];
void add(int i,int x,int y){
e[i].pre=head[x];
e[i].to=y;
head[x]=i;
}
void dfs1(int x){
size[x]=;
for(int i=head[x];i;i=e[i].pre){
if(e[i].to==fa[x])continue;
dep[e[i].to]=dep[x]+;
fa[e[i].to]=x;
dfs1(e[i].to);
size[x]+=size[e[i].to];
}
}
void dfs2(int x,int ding){
int k=;sz++;
pos[x]=sz;top[x]=ding;
for(int i=head[x];i;i=e[i].pre)
if(dep[e[i].to]>dep[x]&&size[e[i].to]>size[k])
k=e[i].to;
if(!k)return;
dfs2(k,ding);
for(int i=head[x];i;i=e[i].pre)
if(dep[e[i].to]>dep[x]&&e[i].to!=k)
dfs2(e[i].to,e[i].to);
}
void push_up(int now){
sum[now]=sum[now*]+sum[now*+];
mx[now]=max(mx[now*],mx[now*+]);
}
void change(int x,int y,int l,int r,int now){
if(l==r){
sum[now]=mx[now]=y;return;
}
int mid=(l+r)>>;
if(x<=mid)change(x,y,lson);
else change(x,y,rson);
push_up(now);
}
int quirysum(int x,int y,int l,int r,int now){
if(l>=x&&r<=y)return sum[now];
int mid=(l+r)>>,tot=;
if(x<=mid)tot+=quirysum(x,y,lson);
if(y>mid)tot+=quirysum(x,y,rson);
return tot;
}
int quirymx(int x,int y,int l,int r,int now){
if(l>=x&&r<=y)return mx[now];
int mid=(l+r)>>,tot=-inf;
if(x<=mid)tot=max(tot,quirymx(x,y,lson));
if(y>mid)tot=max(tot,quirymx(x,y,rson));
return tot;
}
int solvesum(int x,int y){
int tot=;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
tot+=quirysum(pos[top[x]],pos[x],,n,);
x=fa[top[x]];
}
if(pos[x]>pos[y])swap(x,y);
tot+=quirysum(pos[x],pos[y],,n,);
return tot;
}
int solvemx(int x,int y){
int mx=-inf;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
mx=max(mx,quirymx(pos[top[x]],pos[x],,n,));
x=fa[top[x]];
}
if(pos[x]>pos[y])swap(x,y);
mx=max(mx,quirymx(pos[x],pos[y],,n,));
return mx;
}
int main(){
scanf("%d",&n);
for(int i=;i<n;i++){
int x,y;scanf("%d%d",&x,&y);
add(i*-,x,y);add(i*,y,x);
}
for(int i=;i<=n;i++)scanf("%d",&v[i]);
dfs1();dfs2(,);
for(int i=;i<=n;i++)change(pos[i],v[i],,n,);
scanf("%d",&m);char ch[];
while(m--){
int x,y;scanf("%s%d%d",ch,&x,&y);
if(ch[]=='C'){v[x]=y;change(pos[x],y,,n,);}
else {
if(ch[]=='M')printf("%d\n",solvemx(x,y));
else printf("%d\n",solvesum(x,y));
}
}
return ;
}
最后贴一个很好的ppt:http://wenku.baidu.com/link?url=SGLjpJtYbJ0HxDYlU_GMXE1qCFS0gbmpDGWPxI7mQuNAsJP0y872mNKwpZ8P054g5XMhFGZbMUjZvN5hcnxFFUEfGBj6-tnkpnJvnVSlqGS
新学了LCT,也可以搞这个题目。
#include<cstdio>
#include<iostream>
#define N 30010
#define inf 1000000000
using namespace std;
int u[N],v[N],w[N],c[N][],fa[N],mx[N],sum[N],rev[N],st[N],n,m;
bool isroot(int x){
return c[fa[x]][]!=x&&c[fa[x]][]!=x;
}
void update(int x){
int l=c[x][],r=c[x][];
sum[x]=w[x]+sum[l]+sum[r];
mx[x]=max(w[x],max(mx[l],mx[r]));
}
void pushdown(int x){
int l=c[x][],r=c[x][];
if(rev[x]){
rev[x]^=;rev[l]^=;rev[r]^=;
swap(c[x][],c[x][]);
}
}
void rotate(int x){
int y=fa[x],z=fa[y],l,r;
if(c[y][]==x) l=;else l=;r=l^;
if(!isroot(y)){
if(c[z][]==y) c[z][]=x;else c[z][]=x;
}
fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
c[y][l]=c[x][r];c[x][r]=y;
update(y);update(x);
}
void splay(int x){
int top=;st[++top]=x;
for(int i=x;!isroot(i);i=fa[i])
st[++top]=fa[i];
for(int i=top;i;i--) pushdown(st[i]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y)){
if(c[y][]==x^c[z][]==y) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x){
for(int t=;x;t=x,x=fa[x])
splay(x),c[x][]=t,update(x);
}
void makeroot(int x){
access(x);splay(x);rev[x]^=;
}
void join(int x,int y){
makeroot(x);fa[x]=y;splay(x);
}
void query(int x,int y){//在查询的时候,先将x转到根节点,再将y转到根节点,此时y的值就是所求值
makeroot(x);access(y);splay(y);
}
int main(){
scanf("%d",&n);mx[]=-inf;//mx忘记赋最小值了,1WA
for(int i=;i<n;i++)
scanf("%d%d",&u[i],&v[i]);
for(int i=;i<=n;i++){
scanf("%d",&w[i]);
sum[i]=mx[i]=w[i];
}
for(int i=;i<n;i++)
join(u[i],v[i]);
scanf("%d",&m);
char ch[];int x,y;
for(int i=;i<=m;i++){
scanf("%s%d%d",ch,&x,&y);
if(ch[]=='C'){
splay(x);
w[x]=y;
update(x);
}
else if(ch[]=='Q'&&ch[]=='M'){
query(x,y);
printf("%d\n",mx[y]);
}
else {
query(x,y);
printf("%d\n",sum[y]);
}
}
return ;
}
数的统计count(bzoj1036)的更多相关文章
- [BZOJ1036][ZJOI2008]树的统计Count 解题报告|树链剖分
树链剖分 简单来说就是数据结构在树上的应用.常用的为线段树splay等.(可现在splay还不会敲囧) 重链剖分: 将树上的边分成轻链和重链. 重边为每个节点到它子树最大的儿子的边,其余为轻边. 设( ...
- 【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分
[BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. ...
- bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题
[ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u ...
- bzoj1036 [ZJOI2008]树的统计Count
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MB Submit: 12646 Solved: 5085 [Subm ...
- BZOJ-1036 树的统计Count 链剖线段树(模板)=(树链剖分+线段树)
潇爷昨天刚刚讲完...感觉得还可以...对着模板打了个模板...还是不喜欢用指针.... 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Lim ...
- bzoj千题计划124:bzoj1036: [ZJOI2008]树的统计Count
http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分板子题 #include<cstdio> #include<iost ...
- BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]【学习笔记】
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 14302 Solved: 5779[Submit ...
- PowerShell调用jira rest api实现对个人提交bug数的统计
通过PowerShell的invoke-webrequest和net.client联合实现个人指定项目jira提交数的统计,其中涉及到了JSON对象的提交,代码如下: $content = @{use ...
- BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 14982 Solved: 6081[Submit ...
随机推荐
- Ubuntu 14 常用“快捷键”,Ctrl + Alt + F1 进入终端,按 Ctrl + Alt + F7 回到界面
Ubuntu中所谓 Super键,就是 Windows建,一般在键盘的 ctrl 和 alt 2个键之间,一个微软窗口的图标. 1.持续按住 Super键,会弹出“键盘快捷键”大全: 2.修改快捷键路 ...
- 用jQuery编的一个分页小代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 安装JBPM6运行环境(JBPM6学习之二)
安装Eclipse插件成功后,需要配置JBPM6的运行环境: 1. 第一步先将下载的jbpm6目录中的“jbpm-6.0.1.Final-bin.zip”找到,并解压缩到D盘根目录备用. 2. 第二步 ...
- 简述JavaScript函数节流
为什么要用函数节流 浏览器中某些计算和处理要比其他的昂贵很多.例如,DOM 操作比起非 DOM 交互需要更多的内存和 CPU 时间.连续尝试进行过多的 DOM 相关操作可能会导致浏览器挂起,有时候甚至 ...
- 14个Xcode中常用的快捷键操作(转)
2014-12-24 17:31 编辑: suiling 分类:iOS开发 来源:iPhoneDev.tv 13 31621 Xcode 6Xcode快捷键 招聘信息: 开发工程师 iOS开发工程师 ...
- django的信号
Django中提供了“信号调度”,用于在框架执行操作时解耦.通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者. 1.Django内置信号 Model signals pre_in ...
- EOS/普元:概述:中国IT业的悲哀
公司引入了普元的EOS作为公司的基础架构平台,今后的所有项目将逐步向EOS的迁移,但对EOS的研究又让我不得不说出以下话: 1.EOS确实够简单,但未免简单过了头:从语言层面看EOS 因为EOS将成为 ...
- fstream的使用方法介绍
转载自: fstream的使用方法介绍 - saga's blog - C++博客 http://www.cppblog.com/saga/archive/2007/06/19/26652.html ...
- Appium+Robotframework实现Android应用的自动化测试-6:一个简单的例子
万事具备,只欠编码! 下面看一个简单的示例,这个示例验证Android手机自带的通讯录的添加联系人的操作是否成功.这个例子是Appium官网自带的示例,有兴趣的同学也可以自己下载来研究和学习,下载地址 ...
- Unity3d 解析文本执行已注册的自定函数
最近有个需求是想让程序解析策划编辑一个文本生成一段CG,内容使用大致是这样 cgSetCameraEx(118.6324,30.71189,75.55666,45,-45,0,0) cgCloneMy ...