码迷,mamicode.com
首页 > 其他好文 > 详细

[bzoj3999] [TJOI2015]旅游

时间:2018-12-30 02:48:52      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:sample   turn   namespace   选择   std   之间   [1]   ace   两种   

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;
}

[bzoj3999] [TJOI2015]旅游

标签:sample   turn   namespace   选择   std   之间   [1]   ace   两种   

原文地址:https://www.cnblogs.com/hbyer/p/10198113.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!