[bzoj3999] [TJOI2015]旅游
Description
为了提高智商,ZJY准备去往一个新世界去旅游。这个世界的城市布局像一棵树。每两座城市之间只有一条路径可
以互达。每座城市都有一种宝石,有一定的价格。ZJY为了赚取最高利益,她会选择从A城市买入再转手卖到B城市
。由于ZJY买宝石时经常卖萌,因而凡是ZJY路过的城市,这座城市的宝石价格会上涨。让我们来算算ZJY旅游完之
后能够赚取的最大利润。(如a城市宝石价格为v,则ZJY出售价格也为v)
Input
第一行输入一个正整数N,表示城市个数。
接下来一行输入N个正整数表示每座城市宝石的最初价格p,每个宝石的初始价格不超过100。
第三行开始连续输入N-1行,每行有两个数字x和y。表示x城市和y城市有一条路径。城市编号从1开始。
下一行输入一个整数Q,表示询问次数。
接下来Q行,每行输入三个正整数a,b,v,表示ZJY从a旅游到b,城市宝石上涨v。
1≤ N≤50000, 1≤Q ≤50000
Output
对于每次询问,输出ZJY可能获得的最大利润,如果亏本则输出0。
Sample Input
3
1 2 3
1 2
2 3
2
1 2 100
1 3 100
Sample Output
1
1
Solution
链上信息,考虑\(LCT\)维护(才不是因为树剖太神奇不会写呢)
维护四个信息:区间最小值,最大值,最小收益,最大收益。
注意这里的最小收益可以是负数,即低价买入高价卖出。
然后最大收益分两种情况更新:左边买入右边卖出,或者在同一边买入卖出。
注意\(reverse\)的时候最大收益一定是最小收益的相反数,即卖出的地方买入,买入的地方卖出,所以最大收益和最小收益取个相反数,\(swap\)一下就好了。
剩下的都是板子啦~
#include<bits/stdc++.h>
using namespace std;
#define ONLINE_JUDGE
#ifdef ONLINE_JUDGE
#define getchar() ((p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2)?EOF:*p1++)
#endif
namespace fast_IO {
char buf[1<<21],*p1=buf,*p2=buf;
template <typename T> inline void read(T &x) {
x=0;T f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
template <typename T,typename ...Args> inline void read(T &x,Args &...args) {
read(x),read(args...);
}
char buf2[1<<21],a[100];int p,p3=-1;
inline void flush() {fwrite(buf2,1,p3+1,stdout),p3=-1;}
template <typename T> inline void write(T x) {
if(p3>1<<20) flush();
if(x<0) x=-x,buf2[++p3]='-';
do {a[++p]=x%10+48;} while(x/=10);
do {buf2[++p3]=a[p];} while(--p);
buf2[++p3]='\n';
}
template <typename T,typename ...Args> inline void write(T x,Args ...args) {
write(x),write(args...);
}
}
using fast_IO :: read;
using fast_IO :: write;
using fast_IO :: flush;
const int maxn = 2e5+10;
int n,m;
struct Link_Cut_Tree {
int fa[maxn],son[maxn][2],rev[maxn],tag[maxn],mn[maxn],mx[maxn],val[maxn],mnans[maxn],mxans[maxn];
void update(int x) {
mn[x]=mx[x]=val[x],mnans[x]=mxans[x]=0;
if(son[x][0]) {
mnans[x]=min(min(mnans[x],mnans[son[x][0]]),mn[x]-mx[son[x][0]]);
mxans[x]=max(max(mxans[x],mxans[son[x][0]]),mx[x]-mn[son[x][0]]);
mn[x]=min(mn[x],mn[son[x][0]]),mx[x]=max(mx[x],mx[son[x][0]]);
}
if(son[x][1]) {
mnans[x]=min(min(mnans[x],mnans[son[x][1]]),mn[son[x][1]]-mx[x]);
mxans[x]=max(max(mxans[x],mxans[son[x][1]]),mx[son[x][1]]-mn[x]);
mn[x]=min(mn[x],mn[son[x][1]]),mx[x]=max(mx[x],mx[son[x][1]]);
}
}
void push_rev(int x) {
if(!x) return ;
swap(son[x][0],son[x][1]),swap(mxans[x],mnans[x]);
rev[x]^=1,mnans[x]*=-1,mxans[x]*=-1;
}
void push_tag(int x,int v) {
if(x) mn[x]+=v,mx[x]+=v,tag[x]+=v,val[x]+=v;
}
void pushdown(int x) {
if(tag[x]) push_tag(son[x][0],tag[x]),push_tag(son[x][1],tag[x]),tag[x]=0;
if(rev[x]) rev[x]^=1,push_rev(son[x][0]),push_rev(son[x][1]);
}
int is_root(int x) {return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;}
int which(int x) {return son[fa[x]][1]==x;}
void rotate(int x) {
int f=fa[x],ff=fa[f],w=which(x);
if(!is_root(f)) son[ff][son[ff][1]==f]=x;
fa[f]=x,fa[x]=ff,fa[son[x][w^1]]=f,son[f][w]=son[x][w^1],son[x][w^1]=f;
update(f),update(x);
}
int sta[maxn];
void splay(int x) {
int top=0,t=x;
while(!is_root(t)) sta[++top]=t,t=fa[t];sta[++top]=t;
while(top) pushdown(sta[top--]);
while(!is_root(x)) {
int y=fa[x],z=fa[y];
if(!is_root(y)) rotate(((son[y][1]==x)^(son[z][1]==y))?x:y);
rotate(x);
}update(x);
}
void access(int x) {
for(int t=0;x;t=x,x=fa[x]) splay(x),son[x][1]=t,update(x);
}
void make_root(int x) {
access(x),splay(x),push_rev(x);
}
void link(int x,int y) {
make_root(x),access(y),splay(y);fa[x]=y;
}
void modify(int x,int y,int v) {
make_root(x),access(y),splay(y),push_tag(y,v);
}
int query(int x,int y) {
make_root(x),access(y),splay(y);return max(mxans[y],0);
}
}LCT;
int main() {
read(n);for(int i=1;i<=n;i++) read(LCT.val[i]);
for(int i=1,x,y;i<n;i++) read(x,y),LCT.link(x,y);read(m);
for(int i=1,x,y,z;i<=m;i++)
read(x,y,z),write(LCT.query(x,y)),LCT.modify(x,y,z);
flush();
return 0;
}