题目
一棵带点权的树上
每次询问查找
x
−
>
y
x->y
x−>y的路径上先经过
u
u
u,再经过
v
v
v,
a
v
−
a
u
a_v-a_u
av−au的最大值
之后将
x
−
>
y
x->y
x−>y路径每个点权加
v
v
v
题解
额。。。不知道是出题人还是我的语文有问题,我开始认为是一次询问可以多次买入卖出,然后就搞了一个乱七八糟的序列dp,然后炸掉。。。
树剖好 题
思考怎样求答案
假设我们己经将左边,右边的求好了,要合并信息到一起
一共三种情况
①
a
n
s
=
a
n
s
l
②
a
n
s
=
a
n
s
r
③
a
n
s
=
m
a
x
r
−
m
i
n
l
①ans=ans_l\\②ans=ans_r\\③ans=max_r-min_l
①ans=ansl②ans=ansr③ans=maxr−minl
由此可以简单得到我们线段树需要维护的三个值区间最大,最小和
a
n
s
ans
ans
但树剖的时候发现
x
−
>
y
x->y
x−>y与
y
−
>
x
y->x
y−>x是不一样的
所以需要求另一个反过来
a
n
s
′
=
m
a
x
l
−
m
i
n
r
ans'=max_l-min_r
ans′=maxl−minr
以后这种复杂的合并可以考虑用单独函数帮助,代码或许就很简洁好调了吧
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10,M=2*N,INF=1e9;
int n,m;
int a[N],b[N];
int head[N],nex[M],to[M],tot;
void build(int u,int v){tot++;nex[tot]=head[u];to[tot]=v;head[u]=tot;}
//-
#define ls lson[x]
#define rs rson[x]
int lson[N*4],rson[N*4],tag[N*4];
int t[N*4][2],maxx[N*4],minn[N*4];
void updata(int x)
{
if(ls&&rs)
{
t[x][0]=max(max(t[ls][0],t[rs][0]),maxx[rs]-minn[ls]);
t[x][1]=max(max(t[ls][1],t[rs][1]),maxx[ls]-minn[rs]);
minn[x]=min(minn[ls],minn[rs]),maxx[x]=max(maxx[ls],maxx[rs]);
}
else if(ls)t[x][0]=t[ls][0],t[x][1]=t[ls][1],minn[x]=minn[ls],maxx[x]=maxx[ls];
else if(rs)t[x][1]=t[rs][0],t[x][1]=t[rs][1],minn[x]=minn[rs],maxx[x]=maxx[rs];
}
void pushdown(int x)
{
if(ls)maxx[ls]+=tag[x],minn[ls]+=tag[x],tag[ls]+=tag[x];
if(rs)maxx[rs]+=tag[x],minn[rs]+=tag[x],tag[rs]+=tag[x];
tag[x]=0;
}
void build(int x,int l,int r)
{
if(l==r){maxx[x]=minn[x]=b[l];return ;}
int mid=(l+r)>>1;
build(ls=x<<1,l,mid);build(rs=x<<1|1,mid+1,r);
updata(x);
}
int key;
void add(int x,int l,int r,int ll,int rr)
{
pushdown(x);
if(ll<=l&&r<=rr){tag[x]+=key;maxx[x]+=key;minn[x]+=key;return ;}
int mid=(l+r)>>1;
if(ll<=mid)add(ls,l,mid,ll,rr);
if(mid<rr) add(rs,mid+1,r,ll,rr);
updata(x);
}
void qur(int x,int l,int r,int ll,int rr,int &Mi,int &Ma,int &Tmp0,int &Tmp1)
{
pushdown(x);
if(ll<=l&&r<=rr)
{
Mi=minn[x],Tmp0=t[x][0];
Ma=maxx[x],Tmp1=t[x][1];
return ;
}
int mid=(l+r)>>1;
if(rr<=mid) qur(ls,l,mid ,ll,rr,Mi,Ma,Tmp0,Tmp1);
else if(mid<ll) qur(rs,mid+1,r,ll,rr,Mi,Ma,Tmp0,Tmp1);
else
{
int lmi,rmi,lma,rma,ltmp0,ltmp1,rtmp0,rtmp1;
qur(ls,l,mid, ll,rr,lmi,lma,ltmp0,ltmp1);
qur(rs,mid+1,r,ll,rr,rmi,rma,rtmp0,rtmp1);
Tmp0=max(max(ltmp0,rtmp0),rma-lmi);
Tmp1=max(max(ltmp1,rtmp1),lma-rmi);
Mi=min(lmi,rmi);Ma=max(lma,rma);
}
updata(x);
}
//--
int tp[N],son[N],fa[N],dep[N],dfn[N],sz[N],cnt;
void dfs1(int u,int f)
{
sz[u]=1;dep[u]=dep[f]+1;fa[u]=f;
for(int i=head[u];i;i=nex[i])
{
int v=to[i];if(v==f)continue;
dfs1(v,u);sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
void dfs2(int u,int f)
{
tp[u]=f;dfn[u]=++cnt;b[cnt]=a[u];
if(son[u])dfs2(son[u],f);
for(int i=head[u];i;i=nex[i])
{
int v=to[i];if(dfn[v])continue;
dfs2(v,v);
}
}
void Q_add(int x,int y)
{
while(tp[x]^tp[y])
{
if(dep[tp[x]]<dep[tp[y]])swap(x,y);
add(1,1,n,dfn[tp[x]],dfn[x]);
x=fa[tp[x]];
}
if(dep[x]<dep[y])swap(x,y);
add(1,1,n,dfn[y],dfn[x]);
}
int Q_qur(int x,int y)
{
int ans=0;
int lma=0,lmi=1e9;
int rma=0,rmi=1e9;
int fma=0,fmi=0,ftmp0=0,ftmp1=0;
while(tp[x]^tp[y])
{
if(dep[tp[x]]>dep[tp[y]])
{
qur(1,1,n,dfn[tp[x]],dfn[x],fmi,fma,ftmp0,ftmp1);
ans=max(ans,max(ftmp1,fma-lmi));
lma=max(lma,fma),lmi=min(lmi,fmi);
x=fa[tp[x]];
}
else
{
qur(1,1,n,dfn[tp[y]],dfn[y],fmi,fma,ftmp0,ftmp1);
ans=max(ans,max(ftmp0,rma-fmi));
rma=max(rma,fma),rmi=min(rmi,fmi);
y=fa[tp[y]];
}
}
if(dep[x]>dep[y])
{
qur(1,1,n,dfn[y],dfn[x],fmi,fma,ftmp0,ftmp1);
ans=max(ans,max(ftmp1,fma-lmi));
lma=max(lma,fma),lmi=min(lmi,fmi);
}
else
{
qur(1,1,n,dfn[x],dfn[y],fmi,fma,ftmp0,ftmp1);
ans=max(ans,max(ftmp0,rma-fmi));
rma=max(rma,fma),rmi=min(rmi,fmi);
}
ans=max(ans,rma-lmi);
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int x,y,i=1;i<n;i++)scanf("%d%d",&x,&y),build(x,y),build(y,x);
memset(minn,0x7f,sizeof(minn));
dfs1(1,0);dfs2(1,1);build(1,1,n);
scanf("%d",&m);
while(m--)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
printf("%d\n",Q_qur(x,y));
key=z;Q_add(x,y);
}
}