Time:2016.05.26
Author:xiaoyimi
转载注明出处谢谢
传送门
思路:
(调了好久发现是链剖打错了)
线性版本的话可以去看水果姐逛水果店Ⅰ
这个放到了树上,还加了个修改操作
先链剖,再维护最大值及最小值,左->右最大差值,右->左最大差值
区间修改打标记
线段树上的连续区间维护起来很好办
关键就在于怎么维护询问中访问的所有链的信息
之前没有写过类似这样的,向char哥学习了一下,具体就是线段树查询时返回线段树的数据类型的节点,来存储和维护信息。
细节信息个人推荐看代码
注意:
很容易把左右,大小,深浅这些东西搞混了……最后就不知所措= =
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#define M 50003
#define inf 0x7ffffff
using namespace std;
int n,q,tot,cnt;
int w[M],fa[M],son[M],siz[M],top[M],dep[M],L[M],pre[M],first[M],lazy[M<<2];
struct edge{int v,next;}e[M<<1];
struct seg
{
int sum_L,sum_R,maxn,minn;
//sum_L->由深到浅(线段树区间由大到小走),sum_R->由浅到深(线段树区间由小到大)
}tree[M<<2];
seg Null={-inf,-inf,-inf,inf};
int in()
{
int t=0;char ch=getchar();bool f=0;
while (!isdigit(ch)) f=(ch=='-'),ch=getchar();
while (isdigit(ch)) t=(t<<1)+(t<<3)+ch-48,ch=getchar();
return f?-t:t;
}
void add(int x,int y)
{
e[++tot]=(edge){y,first[x]};first[x]=tot;
e[++tot]=(edge){x,first[y]};first[y]=tot;
}
void dfs1(int x)
{
siz[x]=1;
for (int i=first[x];i;i=e[i].next)
if (e[i].v!=fa[x])
fa[e[i].v]=x,
dep[e[i].v]=dep[x]+1,
dfs1(e[i].v),
siz[x]+=siz[e[i].v],
son[x]=(siz[son[x]]>siz[e[i].v]?son[x]:e[i].v);
}
void dfs2(int x,int tp)
{
L[x]=++cnt;
pre[cnt]=x;
top[x]=tp;
if (son[x]) dfs2(son[x],tp);
else return;
for (int i=first[x];i;i=e[i].next)
if (e[i].v!=fa[x]&&e[i].v!=son[x]) dfs2(e[i].v,e[i].v);
}
void pushup(int now)
{
tree[now].maxn=max(tree[now<<1].maxn,tree[now<<1|1].maxn);
tree[now].minn=min(tree[now<<1].minn,tree[now<<1|1].minn);
tree[now].sum_L=max(tree[now<<1].maxn-tree[now<<1|1].minn,
max(tree[now<<1].sum_L,tree[now<<1|1].sum_L));
tree[now].sum_R=max(tree[now<<1|1].maxn-tree[now<<1].minn,
max(tree[now<<1].sum_R,tree[now<<1|1].sum_R));
}
void pushdown(int now)
{
if (!lazy[now]) return;
tree[now<<1].maxn+=lazy[now];
tree[now<<1].minn+=lazy[now];
lazy[now<<1]+=lazy[now];
lazy[now<<1|1]+=lazy[now];
tree[now<<1|1].maxn+=lazy[now];
tree[now<<1|1].minn+=lazy[now];
lazy[now]=0;
}
void build(int now,int begin,int end)
{
if (begin==end)
{
tree[now]=(seg){0,0,w[pre[end]],w[pre[end]]};
return;
}
int mid=begin+end>>1;
build(now<<1,begin,mid);
build(now<<1|1,mid+1,end);
pushup(now);
}
void update(int now,int begin,int end,int l,int r,int val)
{
if (l<=begin&&end<=r)
{
lazy[now]+=val;
tree[now].maxn+=val;
tree[now].minn+=val;
return;
}
pushdown(now);
int mid=begin+end>>1;
if (mid>=l) update(now<<1,begin,mid,l,r,val);
if (mid<r) update(now<<1|1,mid+1,end,l,r,val);
pushup(now);
}
seg get(int now,int begin,int end,int l,int r)
{
if (l<=begin&&end<=r) return tree[now];
pushdown(now);
int mid=begin+end>>1;
if (mid>=r)
return get(now<<1,begin,mid,l,r);
else if (mid<l)
return get(now<<1|1,mid+1,end,l,r);
seg ans,
t1=get(now<<1,begin,mid,l,r),
t2=get(now<<1|1,mid+1,end,l,r);
ans.maxn=max(t1.maxn,t2.maxn);
ans.minn=min(t1.minn,t2.minn);
ans.sum_L=max(max(t1.sum_L,t2.sum_L),t1.maxn-t2.minn);
ans.sum_R=max(max(t1.sum_R,t2.sum_R),t2.maxn-t1.minn);
return ans;
}
main()
{
n=in();
for (int i=1;i<=n;i++) w[i]=in();
for (int i=1;i<n;i++) add(in(),in());
dfs1(1);
dfs2(1,1);
build(1,1,n);
q=in();
int x,y,z;
while (q--)
{
x=in();y=in();z=in();
seg ans_L=Null,ans_R=Null,t;
for (int f1=top[x],f2=top[y];f1!=f2;)
{
if (dep[f1]<dep[f2])
t=get(1,1,n,L[f2],L[y]),
ans_R.sum_R=max(max(ans_R.sum_R,t.sum_R),ans_R.maxn-t.minn),
ans_R.maxn=max(ans_R.maxn,t.maxn),
ans_R.minn=min(ans_R.minn,t.minn),
update(1,1,n,L[f2],L[y],z),
y=fa[f2],f2=top[y];
else
t=get(1,1,n,L[f1],L[x]),
ans_L.sum_L=max(max(ans_L.sum_L,t.sum_L),t.maxn-ans_L.minn),
ans_L.maxn=max(ans_L.maxn,t.maxn),
ans_L.minn=min(ans_L.minn,t.minn),
update(1,1,n,L[f1],L[x],z),
x=fa[f1],f1=top[x];
}
if (dep[x]<=dep[y])
t=get(1,1,n,L[x],L[y]),
ans_R.sum_R=max(max(ans_R.sum_R,t.sum_R),ans_R.maxn-t.minn),
ans_R.maxn=max(ans_R.maxn,t.maxn),
ans_R.minn=min(ans_R.minn,t.minn),
update(1,1,n,L[x],L[y],z);
else
t=get(1,1,n,L[y],L[x]),
ans_L.sum_L=max(max(ans_L.sum_L,t.sum_L),t.maxn-ans_L.minn),
ans_L.maxn=max(ans_L.maxn,t.maxn),
ans_L.minn=min(ans_L.minn,t.minn),
update(1,1,n,L[y],L[x],z);
printf("%d\n",max(ans_R.maxn-ans_L.minn,max(ans_L.sum_L,ans_R.sum_R)));
}
}