[模板]樹鏈剖分
阿新 • • 發佈:2022-05-18
簡易版樹鏈剖分
#include<cstdio> #include<cstring> #include<string> #include<iostream> #define WR WinterRain using namespace std; const int WR=1001000,INF=2147483647; struct SegmentTree{ int l,r,val,sum; }tree[WR]; struct Edge{ int pre,to; }edge[WR]; int n,q; int a[WR]; int head[WR],tot;View Codeint fa[WR],dpt[WR],sze[WR],son[WR]; //fa存父親,dpt存深度,sze存子樹大小,son存重兒子 int top[WR],id[WR],rnk[WR],cnt; int read(){ int s=0,n=1; char ch=getchar(); while(ch>'9'||ch<'0'){ if(ch=='-') n=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=(s<<1)+(s<<3)+ch-48; ch=getchar(); } return s*n; } void pushup(int k){ tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum; tree[k].val=max(tree[k<<1].val,tree[k<<1|1].val); } void build(int k,int l,int r){ tree[k].l=l,tree[k].r=r; if(l==r){ tree[k].val=tree[k].sum=a[rnk[l]];return; } int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); pushup(k); } void modify(int k,int pos,int v){ if(tree[k].l==tree[k].r){ tree[k].val=tree[k].sum=v; return; } int mid=(tree[k].l+tree[k].r)>>1; if(pos<=mid) modify(k<<1,pos,v); else modify(k<<1|1,pos,v); pushup(k); } int query_sum(int k,int l,int r){ if(tree[k].l>=l&&tree[k].r<=r) return tree[k].sum; int mid=(tree[k].l+tree[k].r)>>1,res=0; if(l<=mid) res+=query_sum(k<<1,l,r); if(r>mid) res+=query_sum(k<<1|1,l,r); return res; } int query_max(int k,int l,int r){ if(tree[k].l>=l&&tree[k].r<=r) return tree[k].val; int mid=(tree[k].l+tree[k].r)>>1,res=-INF; if(l<=mid) res=max(res,query_max(k<<1,l,r)); if(r>mid) res=max(res,query_max(k<<1|1,l,r)); return res; } void add(int u,int v){ edge[++tot].pre=head[u]; edge[tot].to=v; head[u]=tot; } void dfs1(int u,int root){ fa[u]=root,dpt[u]=dpt[root]+1,sze[u]=1; for(int i=head[u];i;i=edge[i].pre){ int v=edge[i].to; if(v==root) continue; dfs1(v,u); sze[u]+=sze[v]; if(sze[v]>sze[son[u]]) son[u]=v;//找最大的子樹做重兒子 } } void dfs2(int u,int tp){//tp是目前重鏈的頂端 top[u]=tp,id[u]=++cnt,rnk[cnt]=u;//id和rnk儲存剖分時訪問到的次序 if(son[u]) dfs2(son[u],tp);//有重兒子優先走重兒子 for(int i=head[u];i;i=edge[i].pre){ int v=edge[i].to; if(v!=fa[u]&&v!=son[u]) dfs2(v,v);//如果不是重兒子那麼這個重鏈的頂端是自己 } } int get_sum(int x,int y){ int res=0; while(top[x]!=top[y]){//x,y不在一條鏈上 if(dpt[top[x]]<dpt[top[y]]) swap(x,y);//跳到鏈頂深度更大的 res+=query_sum(1,id[top[x]],id[x]);//區間查詢鏈 x=fa[top[x]];//跳到鏈頂 } if(dpt[x]>dpt[y]) swap(x,y);//確定高低位置 //此時x和y肯定在一條重鏈上 res+=query_sum(1,id[x],id[y]); return res; } int get_max(int x,int y){ int res=-INF; while(top[x]!=top[y]){ if(dpt[top[x]]<dpt[top[y]]) swap(x,y); res=max(res,query_max(1,id[top[x]],id[x])); x=fa[top[x]]; } if(dpt[x]>dpt[y]) swap(x,y); res=max(res,query_max(1,id[x],id[y])); return res; } int main(){ n=read(); for(int i=1;i<n;i++){ int u=read(),v=read(); add(u,v);add(v,u); } for(int i=1;i<=n;i++) a[i]=read(); dfs1(1,0); dfs2(1,1); build(1,1,n); q=read(); for(int i=1;i<=q;i++){ char opt[10]; cin>>opt; int x=read(),y=read(); if(opt[1]=='H') modify(1,id[x],y); if(opt[1]=='S') printf("%d\n",get_sum(x,y)); if(opt[1]=='M') printf("%d\n",get_max(x,y)); } return 0; }