这三道题一个类型的……
第一道题是有一排商店,可以买水果也可以卖水果,买水果和卖水果的价钱一样。
问你从商店x走到商店y,买卖所得最大收益是多少。
我们可以发现朴素的办法是一路扫过去,记录当前最小值,然后更新收益。
这样应该会T(我没试过)
这样丢失了很多信息。
我们考虑一下能不能存起来。
发现解满足区间加法。
即【L,R】中最大的收益要么是【L,K】中的收益,要么是【K,R】中的收益(端点重合不影响),要么是【K,R】中的最大值减去【L,K】中的最小值。这是针对从左往右走的。
于是乎我们可以用线段树来维护这些信息。
因为我们有可能从左往右走,也可能从右往左走,所以记个f数组,f[0]表示从线段树中下标小的向下标大的走所得的最大收益。
合并就是
zkw::node U(const zkw::node &x,const zkw::node &y){
return (zkw::node){
{max(max(x.f[0],y.f[0]),y.max-x.min),
max(max(x.f[1],y.f[1]),x.max-y.min)},
max(x.max,y.max),
min(x.min,y.min)
};
}
而水果姐逛水果街2、3是一个类型,且2是3的子集。
所以我们只讨论3.
树链剖分一下就行了。
关于树链剖分的基础知识请看这里
但是注意一点,这里维护的是点权。
要是查询的两个点一开始就相邻,那么我们要把答案和最后这两个点相遇的那个点上的信息合并一下(要不然你粘贴一下样例会惊喜的发现输出了不该输出的0)。
因为重链上从上到下在线段树中的下标是递增的,所以当把x朝上提的时候,要把tmp的f[0]和f[1]交换一下,达到“从x向上走”的效果。
最后如果x在y的下面,则还需要翻转一下f[0],f[1]。详见代码。
PS:一开始的时候爆栈了,因为我一行读了3个数,跟spoj375搞混了- -
后来我把水果姐2的代码改了一下交3的时候WA了,原来是光改了线段树没改a数组,就70了- -。
ZKW线段树真是快啊!
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=1<<19|1;
const int mm=200001;
int a[200001];
const int inf=1e8+1;
typedef int arr[mm];
typedef int arr1[mm<<1];
arr1 next,to;
arr list,fa,size,top,son,idx,dep;
int n,m,z,tot;
struct zkw{
int M;
struct node{int f[2],max,min;}t[maxn];
void change(int,int);
node query(int,int);
}t;
inline zkw::node U(const zkw::node &x,const zkw::node &y){
return (zkw::node){
{max(max(x.f[0],y.f[0]),y.max-x.min),
max(max(x.f[1],y.f[1]),x.max-y.min)},
max(x.max,y.max),
min(x.min,y.min)
};
}
void zkw::change(int x,int v){
x+=M;
t[x].max=v;
t[x].min=v;
t[x].f[0]=t[x].f[1]=0;
for(x>>=1;x;x>>=1) t[x]=U(t[x<<1],t[x<<1|1]);
}
zkw::node zkw::query(int l,int r){
zkw::node lans={{0},-inf,inf},rans={{0},-inf,inf};
if(l>r) return lans;
for(l+=M-1,r+=M+1;r^l^1;l>>=1,r>>=1){
if(~l&1) lans=U(lans,t[l^1]);
if( r&1) rans=U(t[r^1],rans);
}
return U(lans,rans);
}
inline int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=x*10+ch-48,ch=getchar();
return x;
}
void dfs1(int x){
size[x]=1;son[x]=0;
for(int k=list[x];k;k=next[k]){
if(to[k]==fa[x]) continue;
fa[to[k]]=x;
dep[to[k]]=dep[x]+1;
dfs1(to[k]);
if(size[to[k]]>size[son[x]]) son[x]=to[k];
size[x]+=size[to[k]];
}
}
void dfs2(int x,int tp){
top[x]=tp;
idx[x]=++z;
if(son[x]) dfs2(son[x],top[x]);
for(int k=list[x];k;k=next[k])
if(to[k]!=fa[x]&&to[k]!=son[x])
dfs2(to[k],to[k]);
}
inline void add(int a,int b){
tot++;
next[tot]=list[a];
list[a]=tot;
to[tot]=b;
}
int find(int x,int y){
zkw::node ans[2]={(zkw::node){0,0,-inf,inf},(zkw::node){0,0,-inf,inf}},tmp;
int tpx=top[x],tpy=top[y];
while(tpx!=tpy){
if(dep[tpx]>dep[tpy]){//cout<<"a\n";
tmp=t.query(idx[tpx],idx[x]);
swap(tmp.f[0],tmp.f[1]);
// cout<<tpx<<" "<<x<<"\n";
ans[0]=U(ans[0],tmp);
x=fa[tpx];
// ans[0]=U(ans[0],(zkw::node){{0,0},a[x],a[x]});
tpx=top[x];
}else{//cout<<"b\n";
tmp=t.query(idx[tpy],idx[y]);
ans[1]=U(tmp,ans[1]);
y=fa[tpy];
ans[1]=U((zkw::node){{0,0},a[y],a[y]},ans[1]);
tpy=top[y];
}
// cout<<"geg";
}
if(x==y){ return U(ans[0],U((zkw::node){{0,0},a[x],a[x]},ans[1])).f[0];}
if(dep[x]>dep[y]){
tmp=t.query(idx[y],idx[x]);
swap(tmp.f[0],tmp.f[1]);
return U(U(ans[0],tmp),ans[1]).f[0];
}
else return U(U(ans[0],t.query(idx[x],idx[y])),ans[1]).f[0];
}
int d[mm][2];
void init(){
n=read();
t.M=1;
int opt,x,y;
while(t.M<n) t.M<<=1;
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<n;++i){
d[i][0]=read();d[i][1]=read();//读入!!!!!!
// printf("%d %d>\n",d[i][0],d[i][1]);
add(d[i][0],d[i][1]);
add(d[i][1],d[i][0]);
}
dfs1(1);dfs2(1,1);
for(int i=1;i<=n;++i){
t.change(idx[i],a[i]);
}
m=read();
while(m--){
opt=read();
x=read();y=read();
if(opt==1)printf("%d\n",find(x,y));
else a[x]=y,t.change(idx[x],y);
}
}
int main(){
init();
return 0;
}