题目:BZOJ1036、洛谷P2590。
题目大意:
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
我们将以下面的形式来要求你对这棵树完成一些操作:
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身。
解题思路:裸的树链剖分+线段树单点修改、区间查询。
没什么特别的操作。
C++ Code:
#include<cstdio>
#include<cstring>
#include<cctype>
#define N 30005
int n,head[N],fa[N],dep[N],top[N],cnt=0,idx=0,dfn[N],son[N],sz[N];
int a[N];
char opt[11];
struct edge{
int to,nxt;
}e[N<<1];
inline int readint(){
char c=getchar();
bool b=false;
for(;!isdigit(c);c=getchar())b=c=='-';
int d=0;
for(;isdigit(c);c=getchar())
d=(d<<3)+(d<<1)+(c^'0');
return b?-d:d;
}
void dfs(int now){
sz[now]=1;
son[now]=0;
for(int i=head[now];i;i=e[i].nxt)
if(!dep[e[i].to]){
dep[e[i].to]=dep[now]+1;
fa[e[i].to]=now;
dfs(e[i].to);
sz[now]+=sz[e[i].to];
if(!son[now]||sz[son[now]]<sz[e[i].to])
son[now]=e[i].to;
}
}
void dfs2(int now){
dfn[now]=++idx;
if(son[now])top[son[now]]=top[now],dfs2(son[now]);
for(int i=head[now];i;i=e[i].nxt)
if(e[i].to!=son[now]&&dep[e[i].to]>dep[now])
top[e[i].to]=e[i].to,dfs2(e[i].to);
}
class SegmentTree{
private:
struct SegmentTreeNode{
int s,mx;
}d[N<<2];
inline int max(int a,int b){return a>b?a:b;}
int L,R,ans;
void Change(int l,int r,int o){
if(l==r)d[o]=(SegmentTreeNode){R,R};else{
int mid=l+r>>1;
if(L<=mid)Change(l,mid,o<<1);else
Change(mid+1,r,o<<1|1);
d[o].s=d[o<<1].s+d[o<<1|1].s;
d[o].mx=max(d[o<<1].mx,d[o<<1|1].mx);
}
}
void Qmax(int l,int r,int o){
if(L<=l&&r<=R)ans=max(ans,d[o].mx);else{
int mid=l+r>>1;
if(L<=mid)Qmax(l,mid,o<<1);
if(mid<R)Qmax(mid+1,r,o<<1|1);
}
}
void Qsum(int l,int r,int o){
if(L<=l&&r<=R)ans+=d[o].s;else{
int mid=l+r>>1;
if(L<=mid)Qsum(l,mid,o<<1);
if(mid<R)Qsum(mid+1,r,o<<1|1);
}
}
public:
void build_tree(int l,int r,int o){
if(l==r)d[o]=(SegmentTreeNode){a[l],a[l]};else{
int mid=l+r>>1;
build_tree(l,mid,o<<1);
build_tree(mid+1,r,o<<1|1);
d[o].s=d[o<<1].s+d[o<<1|1].s;
d[o].mx=max(d[o<<1].mx,d[o<<1|1].mx);
}
}
inline void change(int u,int t){
L=u,R=t;
Change(1,n,1);
}
inline int qmax(int l,int r){
L=l,R=r;
ans=-0x3fffffff;
Qmax(1,n,1);
return ans;
}
inline int qsum(int l,int r){
L=l,R=r;
ans=0;
Qsum(1,n,1);
return ans;
}
}tree;
int qmax(int x,int y){
int ans=-0x3fffffff;
for(;top[x]!=top[y];)
if(dep[top[x]]>=dep[top[y]]){
int p=tree.qmax(dfn[top[x]],dfn[x]);
if(ans<p)ans=p;
x=fa[top[x]];
}else{
int p=tree.qmax(dfn[top[y]],dfn[y]);
if(ans<p)ans=p;
y=fa[top[y]];
}
int p;
if(dep[x]<dep[y])
p=tree.qmax(dfn[x],dfn[y]);else
p=tree.qmax(dfn[y],dfn[x]);
return ans>p?ans:p;
}
int qsum(int x,int y){
int ans=0;
for(;top[x]!=top[y];)
if(dep[top[x]]>=dep[top[y]]){
ans+=tree.qsum(dfn[top[x]],dfn[x]);
x=fa[top[x]];
}else{
ans+=tree.qsum(dfn[top[y]],dfn[y]);
y=fa[top[y]];
}
if(dep[x]<dep[y])ans+=tree.qsum(dfn[x],dfn[y]);else
ans+=tree.qsum(dfn[y],dfn[x]);
return ans;
}
int main(){
n=readint();
memset(head,0,sizeof head);
for(int i=1;i<n;++i){
int u=readint(),v=readint();
e[++cnt]=(edge){v,head[u]};
head[u]=cnt;
e[++cnt]=(edge){u,head[v]};
head[v]=cnt;
}
memset(dep,0,sizeof dep);
fa[1]=top[1]=dep[1]=1;
dfs(1);dfs2(1);
for(int i=1;i<=n;++i)a[dfn[i]]=readint();
tree.build_tree(1,n,1);
for(int q=readint();q--;){
scanf("%s",opt);
if(opt[1]=='H'){
int u=readint(),t=readint();
tree.change(dfn[u],t);
}else
if(opt[1]=='M'){
int l=readint(),r=readint();
printf("%d
",qmax(l,r));
}else{
int l=readint(),r=readint();
printf("%d
",qsum(l,r));
}
}
return 0;
}