Description
给定一棵 n ( n ≤ 3 × 1 0 4 ) n(n\leq 3\times 10^4) n(n≤3×104)个节点的带点权的树, q ( q ≤ 2 × 1 0 5 ) q(q\leq 2\times 10^5) q(q≤2×105)次操作,操作包括单点权值修改、询问两点间路径节点最大权值和两点间路径所有节点权值和。
Solution
这是一个裸的轻重链剖分题,此处不再陈述算法流程,注意三点细节:
1、 r k rk rk数组的作用—建线段树时子节点 p p p的权值 = a [ r k [ l [ p ] ] ] =a[rk[l[p]]] =a[rk[l[p]]]( r k [ i ] : d f s rk[i]:dfs rk[i]:dfs序为 i i i的节点的序号);
2、时刻注意节点下标与 d f s dfs dfs序对应节点下标的转换;
3、比较最大值:由于点权可能为负,故需注意某些不应初始化为0的变量。
Code
#include<cstdio>
#include<iostream>
#include<string>
#define ri register int
using namespace std;
const int MAXN=3e4+20;
int N,Q,M,a[MAXN],u[MAXN<<1],v[MAXN<<1],fst[MAXN<<1],nxt[MAXN<<1],ui,vi;
int dep[MAXN],fa[MAXN],siz[MAXN],valt[MAXN],son[MAXN],top[MAXN],dfn[MAXN],rk[MAXN],cnt;
int l[MAXN<<2],r[MAXN<<2],sum[MAXN<<2],maxn[MAXN<<2];
string opt;
void dfs1(int x,int father)
{
fa[x]=father,dep[x]=dep[fa[x]]+1,siz[x]=1;
for(ri k=fst[x];k>0;k=nxt[k])
if(v[k]!=fa[x])
{
dfs1(v[k],x);
siz[x]+=siz[v[k]];
if(siz[v[k]]>valt[x])
valt[x]=siz[v[k]],son[x]=v[k];
}
}
void dfs2(int x,int anc)
{
top[x]=anc,dfn[x]=++cnt; rk[dfn[x]]=x;
if(son[x]!=0) dfs2(son[x],anc);
for(ri k=fst[x];k>0;k=nxt[k])
if((v[k]!=fa[x])&&(v[k]!=son[x])) dfs2(v[k],v[k]);
}
void pushup(int p)
{
sum[p]=sum[p <<1]+sum[p <<1|1];
maxn[p]=max(maxn[p <<1],maxn[p <<1|1]);
}
void build(int p,int lft,int rit)
{
l[p]=lft,r[p]=rit;
if(l[p]==r[p])
{
sum[p]=a[rk[l[p]]],maxn[p]=sum[p];
return;
}
ri mid=(lft+rit)>>1;
build(p <<1,lft,mid); build(p <<1|1,mid+1,rit);
pushup(p);
}
void update(int p,int pla,int k)
{
if((l[p]==pla)&&(r[p]==pla))
{
sum[p]=k,maxn[p]=k;
return;
}
if(pla<=r[p <<1]) update(p <<1,pla,k);
if(l[p <<1|1]<=pla) update(p <<1|1,pla,k);
pushup(p);
}
int querymax(int p,int lft,int rit)
{
if(lft<=l[p]&&r[p]<=rit) return maxn[p];
int ans=-1e9;
if(lft<=r[p <<1]) ans=max(ans,querymax(p <<1,lft,rit));
if(l[p <<1|1]<=rit) ans=max(ans,querymax(p <<1|1,lft,rit));
return ans;
}
int LCAqmax(int x,int y)
{
int ans=-1e9;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans=max(ans,querymax(1,dfn[top[x]],dfn[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans=max(ans,querymax(1,dfn[x],dfn[y]));
return ans;
}
int querysum(int p,int lft,int rit)
{
if(lft<=l[p]&&r[p]<=rit) return sum[p];
int ans=0;
if(lft<=r[p <<1]) ans=querysum(p <<1,lft,rit);
if(l[p <<1|1]<=rit) ans+=querysum(p <<1|1,lft,rit);
return ans;
}
int LCAqsum(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=querysum(1,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=querysum(1,dfn[x],dfn[y]);
return ans;
}
int main()
{
std::ios::sync_with_stdio(false);
cin>>N;
M=(N-1)<<1;
for(ri i=1;i<=M;i+=2)
{
cin>>u[i]>>v[i];
nxt[i]=fst[u[i]],fst[u[i]]=i;
u[i+1]=v[i],v[i+1]=u[i];
nxt[i+1]=fst[u[i+1]],fst[u[i+1]]=i+1;
}
for(ri i=1;i<=N;++i) cin>>a[i];
dep[0]=-1;
dfs1(1,0);
dfs2(1,1);
build(1,1,N);
cin>>Q;
for(ri op=1;op<=Q;++op)
{
cin>>opt>>ui>>vi;
if(opt=="CHANGE")
update(1,dfn[ui],vi);
if(opt=="QMAX")
cout<<LCAqmax(ui,vi)<<'\n';
if(opt=="QSUM")
cout<<LCAqsum(ui,vi)<<'\n';
}
return 0;
}