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

————————————————————————————

这题就是典型的树上路径取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——树链剖分的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分)(线段树单点修改)

    [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14968  Solved: 6079[Submit][Stat ...

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

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

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

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

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

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

  10. BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时 ...

随机推荐

  1. Java中的 toString 方法

    1. Object 类中定义有 public String toString() 方法,其返回值是 String 类型,描述当前对象的有关信息: 2. 在进行 String 与其它类型数据的连接操作时 ...

  2. JS DOM视频相关的知识

    1.实现点击a标签改变图片时,如果a的href属性有一个目标网址,但是点击又必须跳转到另外一张图,往往会最后跳转到目标网址,可以在onclick事件函数中加入ruturn false,阻止跳转到页面. ...

  3. 织梦CMS建站入门学习(一)

    一.下载与安装. 首先到织梦官网下载软件,可选择UTF8或GBK不同编码格式,如果电脑没有PHP环境,还要下载dede自带的PHP环境软件. 将软件中的upload文件夹内容复制到WWW文件夹下,然后 ...

  4. Delphi Dataset CurValue

    TField.CurValue Property Represents the current value of the field component including changes made ...

  5. Delphi DBGridEH中,选中行、列、单元格

    // 新增行后,默认首列 procedure TForm1.ADOQuery1AfterInsert(DataSet: TDataSet);begin  with DBGridEh1 do  begi ...

  6. 从一个简单的main方法执行谈谈JVM工作机制

    本来JVM的工作原理浅到可以泛泛而谈,但如果真的想把JVM工作机制弄清楚,实在是很难,涉及到的知识领域太多.所以,本文通过简单的mian方法执行,浅谈JVM工作原理,看看JVM里面都发生了什么. 先上 ...

  7. Selector 模型

    1.服务器端: import selectors import socket sel = selectors.DefaultSelector() #生成一个select对象 def accept(so ...

  8. [BZOJ4036] [HAOI2015]按位或

    传送门:https://lydsy.com/JudgeOnline/problem.php?id=4036 Description 刚开始你有一个数字0,每一秒钟你会随机选择一个[0,2^n-1]的数 ...

  9. [CF888G]Xor-MST

    题目大意:给一个$n$个点的完全图,第$i$个点有点权$v_i$,一条边$x-y$的边权为$v_x\oplus v_y$,求最小生成树 题解:明显$Kruskal$和$Prim$都会$TLE$,有一种 ...

  10. Javascript基础之-强制类型转换(二)

    思考下面这个问题: console.log(+"123"); // 123 console.log(-"123"); // -123 console.log(+ ...