這三道題一個類型的……
第一道題是有一排商店,可以買水果也可以賣水果,買水果和賣水果的價錢一樣。
問你從商店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;
}