考虑用动态点分治来解决像本题这样带修的树上路径问题。
首先对原树进行点分治,建出点分树,在点分树每个节点上用动态开点线段树来维护以该节点为起点,到其点分树子树中每个节点的利润。
查询时只需在点分树上当前所在节点往上跳父亲,在其到点分树根节点的链上的每个节点的线段树上查询。跳到一个节点时,在线段树上查询除了当前节点的利润最大值,同时加上其到当前节点的花费。
修改点权只需在点分树上往上跳父亲,在线段树上单点修改即可。
考虑边权的修改影响的是当前根所对应的一个子树,对于边权的修改,从其两个端点在点分树上深度更大,即点分治递归层数更深的点开始往上跳父亲,每次修改在原树上以当前节点为根,深度更浅的那个端点。
点分树上每个节点的线段树在维护时以节点的 \(dfs\) 序为下标,修改子树信息只需在线段树上区间修改即可。
\(code:\)
#include
#define maxn 100010
#define maxm 200010
#define maxt 3500010
#define inf 1000000000000000
#define mid ((l+r)>>1)
#define mk make_pair
using namespace std;
typedef long long ll;
template inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,q,tree_cnt,dfn_cnt,tot,root,pos=1;
int fa[maxn],ma[maxn],siz[maxn],num[maxn],d[maxn];
int rt[maxn],ls[maxt],rs[maxt],in[20][maxn],out[20][maxn];
ll v[maxn],tag[maxt];
bool vis[maxn];
map,ll> w;
struct edge
{
int to,nxt;
ll v;
}e[maxm];
int head[maxn],edge_cnt;
void add(int from,int to,ll val)
{
e[++edge_cnt]=(edge){to,head[from],val};
head[from]=edge_cnt;
}
struct node
{
ll val;
int id;
}t[maxt];
bool operator <(const node &a,const node &b)
{
if(a.val==b.val) return a.id>b.id;
return a.val=r)
{
pushtag(cur,v);
return;
}
pushdown(cur);
if(L<=mid) modify(L,R,l,mid,v,ls[cur]);
if(R>mid) modify(L,R,mid+1,r,v,rs[cur]);
t[cur]=max(t[ls[cur]],t[rs[cur]]);
}
node query(int L,int R,int l,int r,int cur)
{
if(L>R||!cur) return (node){-inf,0};
if(L<=l&&R>=r) return t[cur];
pushdown(cur);
if(R<=mid) return query(L,R,l,mid,ls[cur]);
if(L>mid) return query(L,R,mid+1,r,rs[cur]);
return max(query(L,R,l,mid,ls[cur]),query(L,R,mid+1,r,rs[cur]));
}
void dfs_root(int x,int fath)
{
siz[x]=1,ma[x]=0;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(vis[y]||y==fath) continue;
dfs_root(y,x),siz[x]+=siz[y],ma[x]=max(ma[x],siz[y]);
}
ma[x]=max(ma[x],tot-siz[x]);
if(ma[x]siz[x]) tot=now-siz[x];
dfs_root(y,x),fa[root]=x,solve(root,depth+1);
}
}
int main()
{
read(n),read(q);
for(int i=1;i<=n;++i) read(v[i]);
for(int i=1;iy) swap(x,y);
w[mk(x,y)]=v;
}
tot=ma[0]=n,dfs_root(1,0),solve(root,1);
while(q--)
{
int opt,x,y,p;
ll val,t;
node ans=(node){-inf,0};
read(opt);
if(opt==1)
{
read(x),read(val);
for(int i=x;i;i=fa[i])
modify(in[d[i]][x],in[d[i]][x],1,num[i],val-v[x],rt[i]);
v[x]=val;
}
else
{
read(x),read(y),read(val);
if(x>y) swap(x,y);
t=w[mk(x,y)]-val,w[mk(x,y)]=val;
if(d[x]in[d[p]][y]) modify(in[d[p]][x],out[d[p]][x],1,num[p],t,rt[p]);
else modify(in[d[p]][y],out[d[p]][y],1,num[p],t,rt[p]);
p=fa[p];
}
}
for(int i=pos;i;i=fa[i])
{
node now=max(query(1,in[d[i]][pos]-1,1,num[i],rt[i]),query(in[d[i]][pos]+1,num[i],1,num[i],rt[i]));
now.val+=query(in[d[i]][pos],in[d[i]][pos],1,num[i],rt[i]).val-v[pos],ans=max(ans,now);
}
printf("%d ",pos=ans.id);
}
return 0;
}