题目大意:给定一棵树,兹磁修改点权,询问两点路径的节点权值和/最大值
题解:树剖裸题,具体见代码
我的收获:树剖第一题……
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
#define root 1,n,1
const int M=30005;
#define INF 0x3f3f3f3f
int n,q,t,tim,x,y;
int fa[M],dep[M],son[M],sz[M],top[M],tree[M],pre[M];//树剖相关
int sum[M<<2],mx[M<<2],v[M],head[M];
char opt[10];
struct edge{int to,nex;}e[M*2];
void add(int i,int j){e[t].to=j,e[t].nex=head[i],head[i]=t++;}
void dfs(int x)
//第一遍dfs,处理出dep,size,fa,son
{
sz[x]=1;
//叶子的子树大小为1
for(int i=head[x];i!=-1;i=e[i].nex){
int v=e[i].to;
if(v!=fa[x]){
fa[v]=x,dep[v]=dep[x]+1;
dfs(v);sz[x]+=sz[v];
if(!son[x]||sz[v]>sz[son[x]]) son[x]=v;//记录重孩子
}
}
}
void dfs2(int x,int tp)
//连接重边形成重链:以根节点为起点,沿着重边向下拓展,拉成重链,不在当前重链上的节
点,都以该节点为起点向下重新拉一条重链。
{
top[x]=tp;tree[x]=++tim;//top[v]表示v所在的链的顶端节点,tree[v]表示节点v在线段树中的编号
pre[tree[x]]=x;
//pre[v]表示线段树中编号是v的节点所对应的原图中的点(与tree相反)
if(!son[x]) return;
dfs2(son[x],tp);
for(int i=head[x];i!=-1;i=e[i].nex){
int v=e[i].to;
if(v!=son[x]&&v!=fa[x])
dfs2(v,v);
//递归轻儿子
}
}
//以下是线段树
inline void pushup(int x){sum[x]=sum[x<<1]+sum[x<<1|1];mx[x]=max(mx[x<<1],mx[x<<1|1]);}
void build(int l,int r,int x)
{
if(l==r){mx[x]=sum[x]=v[pre[l]];return ;}
//这里注意是pre[l]
int m=(l+r)>>1;
build(lson);build(rson);
pushup(x);
}
void updata(int p,int v,int l,int r,int x)
{
if(l==r){mx[x]=sum[x]=v;return ;}
int m=(l+r)>>1;
if(p<=m) updata(p,v,lson);
else updata(p,v,rson);
pushup(x);
}
int query_sum(int L,int R,int l,int r,int x)
{
if(L<=l&&r<=R) return sum[x];
int m=(l+r)>>1,ans=0;
if(L<=m) ans+=query_sum(L,R,lson);
if(R>m) ans+=query_sum(L,R,rson);
return ans;
}
int query_max(int L,int R,int l,int r,int x)
{
if(L<=l&&r<=R) return mx[x];
int m=(l+r)>>1,ans=-INF;
//有负数,所以不能初始化为0
if(L<=m) ans=max(ans,query_max(L,R,lson));
if(R>m) ans=max(ans,query_max(L,R,rson));
return ans;
}
int find_sum(int x,int y)
{
int f1=top[x],f2=top[y],ans=0;
while(f1!=f2)
//一边查询,一边往一条重链上靠
{
if(dep[f1]<dep[f2]) swap(x,y),swap(f1,f2);
ans+=query_sum(tree[f1],tree[x],root);
x=fa[f1];f1=top[x];
}
ans+=dep[x]>dep[y]?query_sum(tree[y],tree[x],root):query_sum(tree[x],tree[y],root);
//到了同一条重链上
return ans;
}
int find_max(int x,int y)
{
int f1=top[x],f2=top[y],ans=-INF;
while(f1!=f2)
{
if(dep[f1]<dep[f2]) swap(x,y),swap(f1,f2);
ans=max(ans,query_max(tree[f1],tree[x],root));
x=fa[f1];f1=top[x];
}
ans=max(ans,dep[x]>dep[y]?query_max(tree[y],tree[x],root):query_max(tree[x],tree[y],root));
return ans;
}
void work()
{
while(q--)
{
scanf("%s%d%d",opt,&x,&y);
if(opt[0]=='C') updata(tree[x],y,root);
else if(opt[1]=='M') printf("%d\n",find_max(x,y));
else printf("%d\n",find_sum(x,y));
}
}
void init()
{
cin>>n;t=0;
memset(head,-1,sizeof(head));
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
for(int i=1;i<=n;i++) scanf("%d",&v[i]);
dfs(1);dfs2(1,1);
build(root);
cin>>q;
}
int main()
{
init();
work();
return 0;
}