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. MFC最基本动作(如创建窗口,点击取消等)函数的执行顺序

    一.MFC应用程序中处理消息的顺序: 1.AfxWndProc()       该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc2.AfxCallWndProc() ...

  2. 活学活用wxPython

    http://www.czug.org/python/wxpythoninaction/

  3. MONyog-数据库性能监控工具

    一.安装步骤 较为简单,网上可以搜索到,此处不做详细说明. 二.使用图解 此处介绍监控数据库连接量.并发量.吞吐量.响应时间等功能 1.设置连接需要监控的数据库 打开:http://127.0.0.1 ...

  4. Jenkins系列-Jenkins插件下载镜像加速

    可供选择的jenkins2 插件镜像列表: Jenkins 所有镜像列表: http://mirrors.jenkins-ci.org/status.html比如日本的镜像: http://mirro ...

  5. str.substring(beginIndex,endIndex)-008

    // 将字符串str前n位放在后面,返回新的字符串 public String headToTail(String str,int n){ if(n==0){ System.out.println(s ...

  6. Java经典设计模式 总览

    一.概况 总体来说设计模式分为三大类: (1)创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. (2)结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥 ...

  7. coreldraw x5提示盗版警告解决方法

    CorelDRAW是一款图形图像软件,大多数用户使用的都是coreldraw x5破解版,所以基本上都收到了coreldraw x5提示盗版警告,导致不能用,没关系,绿茶小编有解决方法. coreld ...

  8. sql 插入列放第一列

    如果是SQLSERVER 的话就这样:select * from dbo.syscolumns where id=OBJECT_ID(N'你的表名') 然后COLID这列就是列的顺序 修改这个字段就行 ...

  9. DELPHI的MEMO组件

    位于Standard选项卡上,它是对EDIT控件的扩展,可以对多行文本进行显示.输入 和编辑. Lines属性: 该属性实际上为TStrings类型的对象,用来存放Memo对象的文本 TStrings ...

  10. Retrofit工具类

    package com.example.week2.retrofitUtils; import android.util.Log; import com.example.week2.model.Con ...