bzoj 1036: [ZJOI2008]树的统计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
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
————————————————————————————
这题就是典型的树上路径取max 路径求和 单点修改了
算法没什么好说的 写了三种写法
1——树链剖分(线段树版)
#include<cstdio>
#include<cstring>
#include<algorithm>
using std::swap;
const int M=;
int read(){
int ans=,f=,c=getchar();
while(c<''||c>''){if(c=='-') f=-; c=getchar();}
while(c>=''&&c<=''){ans=ans*+(c-''); c=getchar();}
return ans*f;
}
int max(int x,int y){return x>y?x:y;}
char ch[];
int n,m;
int first[M],cnt=;
struct node{int to,next;}e[*M];
void ins(int a,int b){e[++cnt]=(node){b,first[a]}; first[a]=cnt;}
void insert(int a,int b){ins(a,b); ins(b,a);}
int fa[M],sz[M],top[M],son[M],id[M],idp=,dep[M];
void f1(int x){
sz[x]=;
for(int i=first[x];i;i=e[i].next){
int now=e[i].to;
if(now==fa[x]) continue;
fa[now]=x; dep[now]=dep[x]+;
f1(now); sz[x]+=sz[now];
if(sz[now]>sz[son[x]]) son[x]=now;
}
}
void f2(int x,int tp){
top[x]=tp; id[x]=idp++;
if(son[x]) f2(son[x],tp);
for(int i=first[x];i;i=e[i].next){
int now=e[i].to;
if(now!=fa[x]&&now!=son[x]) f2(now,now);
}
}
struct pos{int l,r,sum,mx;}tr[*M];
void build(int x,int l,int r){
tr[x].l=l; tr[x].r=r;
if(l==r) return ;
int mid=(l+r)>>;
build(x<<,l,mid); build(x<<^,mid+,r);
}
void up(int x){
tr[x].sum=tr[x<<].sum+tr[x<<^].sum;
tr[x].mx=max(tr[x<<].mx,tr[x<<^].mx);
}
void modify(int x,int s,int y){
if(tr[x].l==tr[x].r) return void(tr[x].sum=tr[x].mx=y);
int mid=(tr[x].l+tr[x].r)>>;
if(mid>=s) modify(x<<,s,y);
else modify(x<<^,s,y);
up(x);
}
int push_max(int x,int L,int R){
if(L<=tr[x].l&&tr[x].r<=R) return tr[x].mx;
int mid=(tr[x].l+tr[x].r)>>,ans=-1e8;
if(L<=mid) ans=max(ans,push_max(x<<,L,R));
if(R>mid) ans=max(ans,push_max(x<<^,L,R));
return ans;
}
int Qmax(int x,int y){
int ans=-1e8;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans=max(ans,push_max(,id[top[x]],id[x]));
x=fa[top[x]]; }
if(id[x]>id[y]) swap(x,y);
ans=max(ans,push_max(,id[x],id[y]));
return ans;
}
int push_sum(int x,int L,int R){
if(L<=tr[x].l&&tr[x].r<=R) return tr[x].sum;
int mid=(tr[x].l+tr[x].r)>>,sum=;
if(L<=mid) sum+=push_sum(x<<,L,R);
if(R>mid) sum+=push_sum(x<<^,L,R);
return sum;
}
int Qsum(int x,int y){
int sum=;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
sum+=push_sum(,id[top[x]],id[x]);
x=fa[top[x]];
}
if(id[x]>id[y]) swap(x,y);
sum+=push_sum(,id[x],id[y]);
return sum;
}
int main(){
int x,y;
n=read(); for(int i=;i<n;i++) x=read(),y=read(),insert(x,y);
f1(); f2(,); build(,,n);
for(int i=;i<=n;i++) x=read(),modify(,id[i],x);
m=read();
for(int i=;i<=m;i++){
scanf("%s",ch); x=read(); y=read();
if(ch[]=='C') modify(,id[x],y);
else if(ch[]=='M') printf("%d\n",Qmax(x,y));
else printf("%d\n",Qsum(x,y));
}
return ;
}
2——树链剖分(zkw线段树版)
#include<cstdio>
#include<cstring>
#include<algorithm>
using std::swap;
const int M=;
int read(){
int ans=,f=,c=getchar();
while(c<''||c>''){if(c=='-') f=-; c=getchar();}
while(c>=''&&c<=''){ans=ans*+(c-''); c=getchar();}
return ans*f;
}
int max(int x,int y){return x>y?x:y;}
char ch[];
int n,m;
int first[M],cnt=;
struct node{int to,next;}e[*M];
void ins(int a,int b){e[++cnt]=(node){b,first[a]}; first[a]=cnt;}
void insert(int a,int b){ins(a,b); ins(b,a);}
int fa[M],sz[M],top[M],son[M],id[M],idp=,dep[M];
void f1(int x){
sz[x]=;
for(int i=first[x];i;i=e[i].next){
int now=e[i].to;
if(now==fa[x]) continue;
fa[now]=x; dep[now]=dep[x]+;
f1(now); sz[x]+=sz[now];
if(sz[now]>sz[son[x]]) son[x]=now;
}
}
void f2(int x,int tp){
top[x]=tp; id[x]=idp++;
if(son[x]) f2(son[x],tp);
for(int i=first[x];i;i=e[i].next){
int now=e[i].to;
if(now!=fa[x]&&now!=son[x]) f2(now,now);
}
}
int ly,s[*M],mx[*M];
void modify(int x,int w){
s[x+ly]=w; mx[x+ly]=w;
for(x=(x+ly)>>;x;x>>=) s[x]=s[x<<]+s[x<<^],mx[x]=max(mx[x<<],mx[x<<^]);
}
int push_max(int l,int r){
int ans=-1e8;
for(l=l+ly-,r=r+ly+;r-l!=;l>>=,r>>=){
if(~l&) ans=max(ans,mx[l^]);
if(r&) ans=max(ans,mx[r^]);
}
return ans;
}
int Qmax(int x,int y){
int ans=-1e8;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans=max(ans,push_max(id[top[x]],id[x]));
x=fa[top[x]];
}
if(id[x]>id[y]) swap(x,y);
ans=max(ans,push_max(id[x],id[y]));
return ans;
}
int push_sum(int l,int r){
int sum=;
for(l=l+ly-,r=r+ly+;r-l!=;l>>=,r>>=){
if(~l&) sum+=s[l^];
if(r&) sum+=s[r^];
}
return sum;
}
int Qsum(int x,int y){
int sum=;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
sum+=push_sum(id[top[x]],id[x]);
x=fa[top[x]];
}
if(id[x]>id[y]) swap(x,y);
sum+=push_sum(id[x],id[y]);
return sum;
}
int main(){
int x,y;
n=read(); ly=; while(ly<=n+) ly<<=;
for(int i=;i<n;i++) x=read(),y=read(),insert(x,y);
f1(); f2(,);
for(int i=;i<=n;i++) x=read(),modify(id[i],x);
m=read();
for(int i=;i<=m;i++){
scanf("%s",ch); x=read(); y=read();
if(ch[]=='C') modify(id[x],y);
else if(ch[]=='M') printf("%d\n",Qmax(x,y));
else printf("%d\n",Qsum(x,y));
}
return ;
}
3——lct(link-cut-tree)
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int M=;
int read(){
int ans=,f=,c=getchar();
while(c<''||c>''){if(c=='-') f=-; c=getchar();}
while(c>=''&&c<=''){ans=ans*+(c-''); c=getchar();}
return ans*f;
}
int n,m,c[M][],fa[M],a[M],b[M];
LL v[M],sum[M],mx[M];
bool rev[M];
bool isrt(int x){return c[fa[x]][]!=x&&c[fa[x]][]!=x;}
void up(int x){
if(!x) return ;
mx[x]=v[x]; sum[x]=v[x];
int l=c[x][],r=c[x][];
if(l) mx[x]=max(mx[x],mx[l]),sum[x]+=sum[l];
if(r) mx[x]=max(mx[x],mx[r]),sum[x]+=sum[r];
}
void down(int x){
if(!rev[x]) return ;
rev[x]=;
int l=c[x][],r=c[x][];
if(l) swap(c[l][],c[l][]),rev[l]^=;
if(r) swap(c[r][],c[r][]),rev[r]^=;
}
void rotate(int x){
int y=fa[x],z=fa[y],l=,r=;
if(c[y][]==x) l=,r=;
if(!isrt(y)) c[z][c[z][]==y]=x;
fa[y]=x; fa[x]=z; fa[c[x][r]]=y;
c[y][l]=c[x][r]; c[x][r]=y;
up(y); up(x);
}
int st[M],top=,S;
void splay(int x){
st[++top]=x; for(int i=x;!isrt(i);i=fa[i]) st[++top]=fa[i];
while(top) down(st[top--]);
while(!isrt(x)){
int y=fa[x],z=fa[y];
if(!isrt(y)){
if(c[z][]==y^c[y][]==x) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void acs(int x0){
for(int x=x0,y=;x;splay(x),c[x][]=y,up(x),y=x,x=fa[x]);
splay(x0);
}
void mrt(int x){acs(x); swap(c[x][],c[x][]); rev[x]^=;}
void link(int x,int y){mrt(x); fa[x]=y;}
void spl(int x,int y){mrt(x); acs(y);}
int main()
{
int x,y;
n=read();
for(int i=;i<n;i++) a[i]=read(),b[i]=read();
for(int i=;i<=n;i++) v[i]=read();
for(int i=;i<n;i++) link(a[i],b[i]);
m=read();
char ch[];
for(int i=;i<=m;i++){
scanf("%s",ch); x=read(); y=read();
if(ch[]=='H') acs(x),v[x]=y;
if(ch[]=='S') spl(x,y),printf("%lld\n",sum[y]);
if(ch[]=='M') spl(x,y),printf("%lld\n",mx[y]);
}
return ;
}
bzoj 1036: [ZJOI2008]树的统计Count——树链剖分的更多相关文章
- BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]【学习笔记】
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 14302 Solved: 5779[Submit ...
- Bzoj 1036: [ZJOI2008]树的统计Count 树链剖分,LCT
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 11102 Solved: 4490[Submit ...
- BZOJ 1036: [ZJOI2008]树的统计Count( 树链剖分 )
树链剖分... 不知道为什么跑这么慢 = = 调了一节课啊跪.. ------------------------------------------------------------------- ...
- 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 ...
- 【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 ...
- 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 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时 ...
随机推荐
- POSIX线程学习
一.什么是线程 在一个程序中的多个执行路线就叫做线程.更准确的定义是:线程是一个进程内部的一个控制序列.所有的进程都至少有一个线程.当进程执行fork调用时,将创建出该进程的一份新副本,这个新进程拥有 ...
- java定时执行任务(一)
需求: 经常遇到这样的需求:要求每天执行一次任务,执行任务时间是凌晨3点 实现: 为了便于检测,我假设的是下一分钟执行任务,每10秒重复执行.(对应现实项目:每天3点执行任务.那么就是下一个3点执行任 ...
- 往Matlab中添加工具包
使用Matlab过程中,常常会缺少一些函数包导致无法运行,会显示未定义函数. 假如我要用sigshift( ) 这个移位函数,但Matlab中没有,就会提示错误:未定义函数或变量 'sigshift' ...
- Uncaught ReferenceError: wx is not defined
程序的分享功能调用了微信的接口,但是忽然发现就报这个错误, Uncaught ReferenceError: wx is not defined 同时下方还有这个错误 This content sho ...
- SQL 中 Date 与Datetime的区别
Date是SQL Server 2008新引进的数据类型.它表示一个日子,不包含时间部分,可以表示的日期范围从公元元年1月1日到9999年12月31日.只需要3个字节的存储空间. DateTime 日 ...
- JavaScript中setInterval常见的问题(setInterval第一个参数加引号与不加引号区别)
- MEX程序中的mexFunction函数【转】
与C中的main函数一样,MEX程序中的开始函数为mexFunction.默认变量参数是: void mexFunction(int nlhs, mxArray *plhs[], int nrhs, ...
- bzoj4502 串
题意:给你n(n<=10000)个字符串,每个字符串的长度不超过30,可以选择两个非空前缀把它们拼起来得到一个字符串(这两个前缀可以来自同一个字符串,也可以是同一个字符串的同一个非空前缀),问得 ...
- 【bzoj1507】[NOI2003]Editor /【bzoj1269】[AHOI2006]文本编辑器editor Splay
[bzoj1507][NOI2003]Editor 题目描述 输入 输入文件editor.in的第一行是指令条数t,以下是需要执行的t个操作.其中: 为了使输入文件便于阅读,Insert操作的字符串中 ...
- 【bzoj1708】[USACO2007 Oct]Money奶牛的硬币 背包dp
题目描述 在创立了她们自己的政权之后,奶牛们决定推广新的货币系统.在强烈的叛逆心理的驱使下,她们准备使用奇怪的面值.在传统的货币系统中,硬币的面值通常是1,5,10,20或25,50,以及100单位的 ...