hdu-4836-The Query on the Tree(線段樹+LCA)
阿新 • • 發佈:2018-12-14
思路:對於每次詢問,主要是看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; }