考虑用动态点分治来解决像本题这样带修的树上路径问题。

首先对原树进行点分治,建出点分树,在点分树每个节点上用动态开点线段树来维护以该节点为起点,到其点分树子树中每个节点的利润。

查询时只需在点分树上当前所在节点往上跳父亲,在其到点分树根节点的链上的每个节点的线段树上查询。跳到一个节点时,在线段树上查询除了当前节点的利润最大值,同时加上其到当前节点的花费。

修改点权只需在点分树上往上跳父亲,在线段树上单点修改即可。

考虑边权的修改影响的是当前根所对应的一个子树,对于边权的修改,从其两个端点在点分树上深度更大,即点分治递归层数更深的点开始往上跳父亲,每次修改在原树上以当前节点为根,深度更浅的那个端点。

点分树上每个节点的线段树在维护时以节点的 \(dfs\) 序为下标,修改子树信息只需在线段树上区间修改即可。

\(code:\)

#include<bits/stdc++.h>
#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<typename T> 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<pair<int,int>,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<b.val;
}
void pushtag(int cur,ll v)
{
t[cur].val+=v,tag[cur]=v;
}
void pushdown(int cur)
{
if(!tag[cur]) return;
pushtag(ls[cur],tag[cur]),pushtag(rs[cur],tag[cur]),tag[cur]=0;
}
void insert(int l,int r,int pos,ll v,int id,int &cur)
{
if(!cur) cur=++tree_cnt;
if(l==r)
{
t[cur]=(node){v,id};
return;
}
if(pos<=mid) insert(l,mid,pos,v,id,ls[cur]);
else insert(mid+1,r,pos,v,id,rs[cur]);
t[cur]=max(t[ls[cur]],t[rs[cur]]);
}
void modify(int L,int R,int l,int r,ll v,int &cur)
{
if(!cur) cur=++tree_cnt;
if(L<=l&&R>=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]<ma[root]) root=x;
}
void dfs_dis(int x,int fath,ll dis,int id)
{
in[d[id]][x]=++dfn_cnt,insert(1,num[id],dfn_cnt,v[x]-dis,x,rt[id]);
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(vis[y]||y==fath) continue;
dfs_dis(y,x,dis+e[i].v,id);
}
out[d[id]][x]=dfn_cnt;
}
void solve(int x,int depth)
{
int now=tot;
d[x]=depth,vis[x]=true,num[x]=now,dfn_cnt=0,dfs_dis(x,0,0,x);
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(vis[y]) continue;
root=0,tot=siz[y];
if(siz[y]>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;i<n;++i)
{
int x,y;
ll v;
read(x),read(y),read(v);
add(x,y,v),add(y,x,v);
if(x>y) 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]<d[y]) p=x;
else p=y;
while(p)
{
if(in[d[p]][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;
}

最新文章

  1. asp.net LINQ连接数据库SQL执行数据的增加、修改、删除、查询操作
  2. c# TCP Socket通讯基础
  3. EntityFramework中几种更改数据的方式
  4. PostgreSQL Replication之第十二章 与Postgres-XC一起工作(4)
  5. ios 开发,通讯录信息调用常用方法,这个比较全,不用再整理了
  6. 腾讯RTX登录提示失败问题及处理办法
  7. android-用xml自定义背景(可自定义显示具体那一边)
  8. 使用bootstrap时,选项框出现的意外效果,怎么办?
  9. Oracle 快照及 dblink使用 (两台服务器数据同步)
  10. java 解决时间相减问题
  11. 浅谈 EF CORE 迁移和实例化的几种方式
  12. UVA 11324 The Largest Clique(强连通分量+缩点DAG的DP)
  13. Docker:私有仓库registry [十一]
  14. Unity如何退出游戏
  15. 【CSS学习】--- position属性
  16. [CF960G] Bandit Blues
  17. lambda List实现某列去重的解决方案采用扩展方法
  18. rabbitmq 配置
  19. VS 在文件中查找替换界面死掉。
  20. 小程序码B接口生成出错:场景内容包含非法字符

热门文章

  1. Python函数参数详解
  2. 入门大数据---Spark部署模式与作业提交
  3. 解Bug之路-中间件&quot;SQL重复执行&quot;
  4. python+opencv图像增强——拉普拉斯
  5. cbitmap 获取RGB
  6. 文档翻译经验分享(Markdown)
  7. spring quartz 每30分钟执行一次cronExpression表达式怎么写
  8. Bash 脚本编程的一些高级用法
  9. 题解 P1144 【最短路计数】
  10. 《算法笔记》6.6小节 问题 A: 任务调度