版权声明:本文为原创文章,转载请标明出处。 https://blog.csdn.net/qq_37171272/article/details/82958513
思路:对于每次询问,主要是看x和root的关系,求出root和xlca
root=x ,ans为总的和
lca=x 那么ans=总的和-(root到x这条链上父节点为x的那个点的子树和)
否则,ans就是x的子树和
求子树和和修改直接线段树维护。节点的编号和lca我是用的树链剖分求的
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+10;
int val[maxn];
struct E
{
int next,to;
}edge[maxn*2];
int head[maxn],deep[maxn],top[maxn],fa[maxn],son[maxn],sz[maxn],id[maxn],fid[maxn],tot,num;
void add_edge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void dfs1(int u,int f,int dep)
{
fa[u]=f;
son[u]=0;
sz[u]=1;
deep[u]=dep;
for(int i=head[u];i!=-1;i=edge[i].next){
int ff=edge[i].to;
if(ff==f) continue;
dfs1(ff,u,dep+1);
sz[u]+=sz[ff];
if(sz[ff]>sz[son[u]]) son[u]=ff;
}
}
void dfs2(int u,int tp)
{
id[u]=++num;
top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int i=head[u];i!=-1;i=edge[i].next){
int ff=edge[i].to;
if(ff==fa[u]||ff==son[u]) continue;
dfs2(ff,ff);
}
}
void init()
{
num=tot=0;
memset(head,-1,sizeof(head));
}
#define ll t[rt].l
#define rr t[rt].r
#define ls rt<<1
#define rs rt<<1|1
struct node
{
int l,r;
int val;
}t[maxn<<2];
void pushup(int rt)
{
t[rt].val=t[ls].val+t[rs].val;
}
void build(int rt,int l,int r)
{
t[rt].l=l;
t[rt].r=r;
if(l==r){
t[rt].val=val[l];
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(rt);
}
void update(int rt,int pos,int v)
{
if(ll==rr){
t[rt].val=v;
return;
}
int mid=(ll+rr)>>1;
if(pos<=mid) update(ls,pos,v);
else update(rs,pos,v);
pushup(rt);
}
int query(int rt,int l,int r)
{
if(l<=ll&&rr<=r) return t[rt].val;
int ans=0;
int mid=(ll+rr)>>1;
if(l<=mid) ans+=query(ls,l,r);
if(r>mid) ans+=query(rs,l,r);
return ans;
}
int Lca(int u,int v)
{
while(top[u]!=top[v]){
if(deep[top[u]]<deep[top[v]]) v=fa[top[v]];
else u=fa[top[u]];
}
return deep[u]<deep[v]?u:v;
}
int Find(int u,int v)///找到离LCA最近的那个点
{
while(top[u]!=top[v]){
if(deep[top[u]]<deep[top[v]]){
if(fa[top[v]]==u) return id[top[v]];
v=fa[top[v]];
}
else{
if(fa[top[u]]==v) return id[top[u]];
u=fa[top[u]];
}
}
if(deep[u]>deep[v]) swap(u,v);
if(u==v) return id[u]+1;
return id[v]-(deep[v]-deep[u])+1;
}
int main()
{
int T;
scanf("%d",&T);
int cas=1;
while(T--){
init();
int n;
scanf("%d",&n);
int u,v;
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
dfs1(1,0,0);
dfs2(1,1);
int x;
for(int i=1;i<=n;i++){
scanf("%d",&x);
val[id[i]]=x;
fid[id[i]]=i;
}
build(1,1,n);
int Q;
scanf("%d",&Q);
char op[8];
int root=1;
printf("Case #%d:\n",cas++);
for(int i=1;i<=Q;i++){
scanf("%s%d",op,&x);
if(op[0]=='Q'){
int lca=Lca(root,x);
int ans;
if(x==root) ans=query(1,1,n);
else if(lca==x){
int p=Find(root,x);
p=fid[p];
ans=query(1,1,n)-query(1,id[p],id[p]+sz[p]-1);
}
else ans=query(1,id[x],id[x]+sz[x]-1);
printf("%d\n",ans);
}
else if(op[0]=='C'){
int v;
scanf("%d",&v);
update(1,id[x],v);
val[id[x]]=v;
}
else{
root=x;
}
}
}
return 0;
}