题目: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; }