题目
思路
这里是求边权,而树剖处理的是点权,怎么办?
对偶图
我们考虑在计算完深度以后,把每一条边的边权记成较深点的点权,因为每个点连向其父亲节点的边唯一,所以不会出现重复赋值。
但这样给我们带来了一个问题,u到v上路径最大边权是不能算LCA(u,v)的。
我们经过部分手(jiao)造树及其对应线段树并手(jiao)玩以后,发现在u,v被推到一根重链上时,设u深度浅,则在线段树里的区间即为
i
d
u
+
1
id_u+1
idu+1至
i
d
v
id_v
idv.
然后树剖即可
code:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
//When I wrote this code,God and I unterstood what was I doing
inline long long read()
{
long long ret,c,f=1;
while (((c=getchar())> '9'||c< '0')&&c!='-');
if (c=='-') f=-1,ret=0;
else ret=c-'0';
while ((c=getchar())>='0'&&c<='9') ret=ret*10+c-'0';
return ret*f;
}
long long xdtree[400020],xdtrees[400020],lazy[400020],a[100005],b[100005],fa[100005],top[100005],zson[100005],dep[100005],id[100005],siz[100005];
long long head[100005],nxt[200010],to[200010],n,m,r,tot,x,y,z;
void dfs1(long long x,long long f)
{
dep[x]=dep[f]+1;
fa[x]=f;
siz[x]=1;
for (long long i=head[x];i;i=nxt[i])
{
if (to[i]==f||to[i]==x) continue;
dfs1(to[i],x);
siz[x]+=siz[to[i]];
if (siz[zson[x]]<siz[to[i]]) zson[x]=to[i];
}
return;
}
void dfs2(long long x,long long f)
{
id[x]=++tot;
b[id[x]]=a[x];
top[x]=f;
if (zson[x]==0) return;
dfs2(zson[x],f);
for (long long i=head[x];i;i=nxt[i])
{
if (id[to[i]]) continue;
dfs2(to[i],to[i]);
}
return;
}
void build(long long l,long long r,long long id)
{
if (l==r)
{
xdtree[id]=xdtrees[id]=b[l];
return;
}
build(l,(l+r)>>1,id*2);
build(((l+r)>>1)+1,r,id*2+1);
xdtree[id]=max(xdtree[id*2],xdtree[id*2+1]);
xdtrees[id]=xdtrees[id*2]+xdtrees[id*2+1];
return;
}
void qjgx(long long l,long long r,long long id,long long L,long long R,long long x)
{
if (l>=L&&R>=r)
{
xdtree[id]=xdtrees[id]=x;
return;
}
long long mid=(l+r)>>1;
if (L<=mid) qjgx(l,mid,id*2,L,R,x);
if (R>mid) qjgx(mid+1,r,id*2+1,L,R,x);
xdtree[id]=max(xdtree[id*2],xdtree[id*2+1]);
xdtrees[id]=xdtrees[id*2]+xdtrees[id*2+1];
return;
}
long long qjcxmx(long long l,long long r,long long id,long long L,long long R)
{
if (l>=L&&R>=r)
{
return xdtree[id];
}
long long mid=(l+r)>>1,ans=-0x7fffffff;
if (L<=mid) ans=max(ans,qjcxmx(l,mid,id*2,L,R));
if (R>mid) ans=max(ans,qjcxmx(mid+1,r,id*2+1,L,R));
return ans;
}
long long qjcx(long long l,long long r,long long id,long long L,long long R)
{
if (l>=L&&R>=r)
{
return xdtrees[id];
}
long long mid=(l+r)>>1,ans=0;
if (L<=mid) ans=ans+qjcx(l,mid,id*2,L,R);
if (R>mid) ans=ans+qjcx(mid+1,r,id*2+1,L,R);
return ans;
}
void treeadd(long long x,long long y,long long z)
{
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
qjgx(1,n,1,id[top[x]],id[x],z);
x=fa[top[x]];
}
if (dep[x]<dep[y]) swap(x,y);
qjgx(1,n,1,id[y],id[x],z);
return;
}
long long treesum(long long x,long long y)
{
long long ans=0;
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
ans=ans+qjcx(1,n,1,id[top[x]],id[x]);
x=fa[top[x]];
}
if (dep[x]<dep[y]) swap(x,y);
ans=ans+qjcx(1,n,1,id[y],id[x]);
return ans;
}
long long treemx(long long x,long long y)
{
long long ans=-0x7fffffff;
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
ans=max(ans,qjcxmx(1,n,1,id[top[x]],id[x]));
x=fa[top[x]];
}
if (dep[x]<dep[y]) swap(x,y);
ans=max(ans,qjcxmx(1,n,1,id[y],id[x]));
return ans;
}
int main()
{
n=read();
for (long long i=1;i<n;i++)
{
x=read(),y=read();
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
to[++tot]=x;
nxt[tot]=head[y];
head[y]=tot;
}
for (long long i=1;i<=n;i++) a[i]=read();
r++;
m=read();
dfs1(r,0);
tot=0;
dfs2(r,r);
build(1,n,1);
string opt;
while (m--)
{
cin>>opt;
if (opt[0]=='C')
{
x=read(),z=read();
qjgx(1,n,1,id[x],id[x],z);
}
if (opt[0]=='Q')
{
x=read(),y=read();
if (opt[1]=='S') cout<<treesum(x,y)<<endl;
else cout<<treemx(x,y)<<endl;
}
}
return 0;
}
//Now,only God know