TJOI2015 旅游
题目链接:戳我
树上有向信息合并。
用树链剖分把其转化为序列上的问题——求区间中最大数-最小数的差,限制为最小数必须在最大数前面选取。
有两种选择方法,一种是先选择全局最大数,在它前面区间中选择最小数。一种是选择全局最小数,然后在它后面的区间种选择最大的。(证明只有这两种情况——加入我们选择了一个全局次大,只有当最小数小于它前面区间最小数才有可能最优,最佳情况下会选到全局最小。但是由于它的全局次大在这个选择的最小数的后面,而这又一定不比选择全局最小+其后面的最大更优)
对于一条链(u,v),我们需要记录四个量——最小值,最大值,u->v的最大差,v->u的最大差(记录后面这两个是因为我们不知道出发点和终点哪一个的dfn更大)
合并后面两个量的时候注意有两种情况,一种是直接取左右儿子中的最大值(也就是左右两个区间内进行选择的最大值),一种是跨区间,需要lson.max-rson.min或者rson.max-lson.min。
然后最后更新答案的时候不要忘了有两种选择方法哦,要分类讨论取最优qwq~
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define check
#define MAXN 100010
#define INF 1e18
using namespace std;
int n,m,tt,cnt;
int head[MAXN],dfn[MAXN],siz[MAXN],dep[MAXN],fa[MAXN],top[MAXN],son[MAXN];
long long p_max[MAXN],p_min[MAXN],q_min[MAXN],q_max[MAXN],w[MAXN],wt[MAXN];
struct Edge{int nxt,to;}edge[MAXN<<1];
struct Node{long long maxx,minn,d,_d,tag;}t[MAXN<<2];
inline int ls(int x){return x<<1;}
inline int rs(int x){return x<<1|1;}
inline void add(int from,int to){edge[++tt].nxt=head[from],edge[tt].to=to,head[from]=tt;}
inline void push_up(int x)
{
t[x].maxx=max(t[ls(x)].maxx,t[rs(x)].maxx);
t[x].minn=min(t[ls(x)].minn,t[rs(x)].minn);
t[x].d=max(t[ls(x)].d,t[rs(x)].d);
t[x].d=max(t[x].d,t[rs(x)].maxx-t[ls(x)].minn);
t[x]._d=max(t[ls(x)]._d,t[rs(x)]._d);
t[x]._d=max(t[x]._d,t[ls(x)].maxx-t[rs(x)].minn);
}
inline void push_down(int x)
{
if(t[x].tag)
{
t[ls(x)].tag+=t[x].tag,t[ls(x)].maxx+=t[x].tag,t[ls(x)].minn+=t[x].tag;
t[rs(x)].tag+=t[x].tag,t[rs(x)].maxx+=t[x].tag,t[rs(x)].minn+=t[x].tag;
t[x].tag=0;
}
}
inline void build(int x,int l,int r)
{
if(l==r){t[x].minn=t[x].maxx=wt[l];t[x].d=t[x]._d=0;return;}
int mid=(l+r)>>1;
build(ls(x),l,mid);
build(rs(x),mid+1,r);
push_up(x);
}
inline void update(int x,int l,int r,int ll,int rr,long long k)
{
if(ll<=l&&r<=rr)
{
t[x].maxx+=k,t[x].minn+=k,t[x].tag+=k;
return;
}
int mid=(l+r)>>1;
push_down(x);
if(ll<=mid) update(ls(x),l,mid,ll,rr,k);
if(mid<rr) update(rs(x),mid+1,r,ll,rr,k);
push_up(x);
}
inline void UPDATE(int x,int y,long long k)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,1,n,dfn[top[x]],dfn[x],k);
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
update(1,1,n,dfn[y],dfn[x],k);
}
inline Node query(int x,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr) return t[x];
int mid=(l+r)>>1;
push_down(x);
Node cur1,cur2,cur3;
cur1.d=cur1._d=0,cur1.maxx=-INF,cur1.minn=INF;
cur2.d=cur2._d=0,cur2.maxx=-INF,cur2.minn=INF;
cur3.d=cur3._d=0,cur3.maxx=-INF,cur3.minn=INF;
if(ll<=mid) cur2=query(ls(x),l,mid,ll,rr);
if(mid<rr) cur3=query(rs(x),mid+1,r,ll,rr);
cur1.maxx=max(cur2.maxx,cur3.maxx);
cur1.minn=min(cur2.minn,cur3.minn);
cur1.d=max(cur2.d,cur3.d);
cur1._d=max(cur2._d,cur3._d);
if(ll<=mid&&mid<rr)
cur1.d=max(cur1.d,cur3.maxx-cur2.minn),cur1._d=max(cur1._d,cur2.maxx-cur3.minn);
return cur1;
}
inline long long QUERY(int x,int y)
{
int cnt1=0,cnt2=0;long long ans=-INF,now_min=INF,now_max=-INF;
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
{
Node cur=query(1,1,n,dfn[top[x]],dfn[x]);
ans=max(ans,cur._d);
p_max[++cnt1]=cur.maxx,p_min[cnt1]=cur.minn;
x=fa[top[x]];
}
else
{
Node cur=query(1,1,n,dfn[top[y]],dfn[y]);
ans=max(ans,cur.d);
q_max[++cnt2]=cur.maxx,q_min[cnt2]=cur.minn;
y=fa[top[y]];
}
}
if(dep[x]<dep[y])
{
Node cur=query(1,1,n,dfn[x],dfn[y]);
ans=max(ans,cur.d);
q_max[++cnt2]=cur.maxx,q_min[cnt2]=cur.minn;
}
else
{
Node cur=query(1,1,n,dfn[y],dfn[x]);
ans=max(ans,cur._d);
p_max[++cnt1]=cur.maxx,p_min[cnt1]=cur.minn;
}
for(int i=cnt2;i>=1;i--) p_max[++cnt1]=q_max[i],p_min[cnt1]=q_min[i];
for(int i=1;i<=cnt1;i++) ans=max(ans,p_max[i]-now_min),now_min=min(now_min,p_min[i]);
for(int i=cnt1;i>=1;i--) ans=max(ans,now_max-p_min[i]),now_max=max(now_max,p_max[i]);
return ans;
}
inline void dfs1(int x,int pre)
{
fa[x]=pre;
dep[x]=dep[pre]+1;
siz[x]=1;
long long maxx=-1;
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==pre) continue;
dfs1(v,x);
siz[x]+=siz[v];
if(siz[v]>maxx) maxx=siz[v],son[x]=v;
}
}
inline void dfs2(int x,int topf)
{
top[x]=topf;
dfn[x]=++cnt;
wt[cnt]=w[x];
if(son[x]) dfs2(son[x],topf);
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==fa[x]||v==son[x]) continue;
dfs2(v,v);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce1.in","r",stdin);
freopen("ce.out","w",stdout);
#endif
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs1(1,1);
dfs2(1,1);
build(1,1,n);
/*for(int i=1;i<=n;i++) printf("son[%d]=%d\n",i,son[i]);puts("");
for(int i=1;i<=n;i++) printf("top[%d]=%d\n",i,top[i]);puts("");
for(int i=1;i<=n;i++) printf("dfn[%d]=%d\n",i,dfn[i]);puts("");*/
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int u,v;long long w;
scanf("%d%d%lld",&u,&v,&w);
printf("%lld\n",QUERY(u,v));
UPDATE(u,v,w);
}
return 0;
}