题目

为了提高智商,ZJY准备去往一个新世界去旅游。这个世界的城市布局像一棵树。每两座城市之间只有一条路径可

以互达。每座城市都有一种宝石,有一定的价格。ZJY为了赚取最高利益,她会选择从A城市买入再转手卖到B城市

。由于ZJY买宝石时经常卖萌,因而凡是ZJY路过的城市,这座城市的宝石价格会上涨。让我们来算算ZJY旅游完之

后能够赚取的最大利润。(如a城市宝石价格为v,则ZJY出售价格也为v)

输入格式

第一行输入一个正整数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

输出格式

对于每次询问,输出ZJY可能获得的最大利润,如果亏本则输出0。

输入样例

3

1 2 3

1 2

2 3

2

1 2 100

1 3 100

输出样例

1

1

题解

题意是树上可修改的两点间有序差值最大值

如果是序列上的话一个线段树维护左右区间最值和答案就可以分类讨论跨不跨过中点得出各个点的答案从而做到维护答案了

如果是树上的话,考虑树剖,将路径拆成了几段几段

答案要么在一段内,要么最值分别分布在两段内

我们就用每一段的答案更新答案,再单独拿出所有的\(O(logn)\)段,考虑相互影响来更新答案

细节上要注意树上路径的方向

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
#define ls (u << 1)
#define rs (u << 1 | 1)
using namespace std;
const int maxn = 50005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int h[maxn],ne = 2;
struct EDGE{int to,nxt;}ed[maxn << 1];
inline void Build(int u,int v){
ed[ne] = (EDGE){v,h[u]}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v]}; h[v] = ne++;
}
int n,A[maxn];
int fa[maxn],siz[maxn],son[maxn],top[maxn],dep[maxn],id[maxn],hash[maxn],cnt;
void dfs1(int u){
siz[u] = 1;
Redge(u) if ((to = ed[k].to) != fa[u]){
fa[to] = u; dep[to] = dep[u] + 1;
dfs1(to);
siz[u] += siz[to];
if (!son[u] || siz[son[u]] < siz[to]) son[u] = to;
}
}
void dfs2(int u,int flag){
id[u] = ++cnt; hash[cnt] = u;
top[u] = flag ? top[fa[u]] : u;
if (son[u]) dfs2(son[u],true);
Redge(u) if ((to = ed[k].to) != fa[u] && to != son[u])
dfs2(to,false);
}
int mx[maxn << 2],mn[maxn << 2],d1[maxn << 2],d2[maxn << 2],tag[maxn << 2];
void upd(int u){
mx[u] = max(mx[ls],mx[rs]);
mn[u] = min(mn[ls],mn[rs]);
d1[u] = max(max(d1[ls],d1[rs]),mx[rs] - mn[ls]);
d2[u] = max(max(d2[ls],d2[rs]),mx[ls] - mn[rs]);
}
void pd(int u){
if (tag[u]){
mx[ls] += tag[u]; mn[ls] += tag[u]; tag[ls] += tag[u];
mx[rs] += tag[u]; mn[rs] += tag[u]; tag[rs] += tag[u];
tag[u] = 0;
}
}
void build(int u,int l,int r){
if (l == r){
mx[u] = mn[u] = A[hash[l]];
return;
}
int mid = l + r >> 1;
build(ls,l,mid);
build(rs,mid + 1,r);
upd(u);
}
void add(int u,int l,int r,int L,int R,int v){
if (l >= L && r <= R){
mx[u] += v; mn[u] += v; tag[u] += v;
return;
}
pd(u);
int mid = l + r >> 1;
if (mid >= L) add(ls,l,mid,L,R,v);
if (mid < R) add(rs,mid + 1,r,L,R,v);
upd(u);
}
struct node{int mx,mn,d1,d2;};
node query(int u,int l,int r,int L,int R){
if (l >= L && r <= R) return (node){mx[u],mn[u],d1[u],d2[u]};
pd(u);
int mid = l + r >> 1;
if (mid >= R) return query(ls,l,mid,L,R);
if (mid < L) return query(rs,mid + 1,r,L,R);
node t1 = query(ls,l,mid,L,R),t2 = query(rs,mid + 1,r,L,R);
return (node){max(t1.mx,t2.mx),min(t1.mn,t2.mn),max(max(t1.d1,t2.d1),t2.mx - t1.mn),max(max(t1.d2,t2.d2),t1.mx - t2.mn)};
}
node st[2][100],e[100];
int Top[2],tot;
void solve(int u,int v,int w){
int p = 0,ans = 0; Top[0] = Top[1] = 0;
while (top[u] != top[v]){
if (dep[top[u]] < dep[top[v]]){
swap(u,v);
p ^= 1;
}
add(1,1,n,id[top[u]],id[u],w);
st[p][++Top[p]] = query(1,1,n,id[top[u]],id[u]);
u = fa[top[u]];
}
p ^= 1;
if (dep[u] > dep[v]){
swap(u,v);
p ^= 1;
}
add(1,1,n,id[u],id[v],w);
st[p][++Top[p]] = query(1,1,n,id[u],id[v]);
tot = 0;
for (int i = 1; i <= Top[0]; i++){
e[++tot] = st[0][i];
ans = max(ans,e[tot].d2);
}
for (int i = Top[1]; i; i--){
e[++tot] = st[1][i];
ans = max(ans,e[tot].d1);
}
int gmin = INF;
for (int i = 1; i <= tot; i++){
ans = max(ans,e[i].mx - gmin);
gmin = min(gmin,e[i].mn);
}
printf("%d\n",ans);
}
int main(){
n = read();
REP(i,n) A[i] = read();
for (int i = 1; i < n; i++) Build(read(),read());
dfs1(1);
dfs2(1,0);
build(1,1,n);
int m = read(),a,b,w;
while (m--){
a = read(); b = read(); w = read();
solve(a,b,w);
}
return 0;
}

BZOJ3999 [TJOI2015]旅游 【树剖 + 线段树】的更多相关文章

  1. BZOJ_2157_旅游_树剖+线段树

    BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...

  2. BZOJ_2238_Mst_树剖+线段树

    BZOJ_2238_Mst_树剖+线段树 Description 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影 ...

  3. BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树

    BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树 Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为 ...

  4. 【BZOJ5210】最大连通子块和 树剖线段树+动态DP

    [BZOJ5210]最大连通子块和 Description 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块 ...

  5. [LNOI2014]LCA(树剖+线段树)

    \(\%\%\% Fading\) 此题是他第一道黑题(我的第一道黑题是蒲公英) 一直不敢开,后来发现是差分一下,将询问离线,树剖+线段树维护即可 \(Code\ Below:\) #include ...

  6. [CF1007D]Ants[2-SAT+树剖+线段树优化建图]

    题意 我们用路径 \((u, v)\) 表示一棵树上从结点 \(u\) 到结点 \(v\) 的最短路径. 给定一棵由 \(n\) 个结点构成的树.你需要用 \(m\) 种不同的颜色为这棵树的树边染色, ...

  7. LOJ#3088. 「GXOI / GZOI2019」旧词(树剖+线段树)

    题面 传送门 题解 先考虑\(k=1\)的情况,我们可以离线处理,从小到大对于每一个\(i\),令\(1\)到\(i\)的路径上每个节点权值增加\(1\),然后对于所有\(x=i\)的询问查一下\(y ...

  8. BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)

    传送门 完了今天才知道原来线段树的动态开点和主席树是不一样的啊 我们先考虑没有宗教信仰的限制,那么就是一个很明显的树剖+线段树,路径查询最大值以及路径和 然后有了宗教信仰的限制该怎么做呢? 先考虑暴力 ...

  9. 【bzoj4699】树上的最短路(树剖+线段树优化建图)

    题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...

  10. POJ3237 Tree(树剖+线段树+lazy标记)

    You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbe ...

随机推荐

  1. C# File和Directory类

    File和Directory类 作为实用类,File和Directory类都提供了许多方法,用于处理文件系统以及其中的文件和目录.这些是静态方法,涉及移动文件.查询和更新属性并创建FileStream ...

  2. jquery的ajax请求

    加载页面内容,如果不加选择器,会加载整个页面内容 加选择器会获取选择器内容 例如: <script> //可以获取json格式的文件 $.ajax({ type:"get&quo ...

  3. 【数学 随机 技巧】cf364D. Ghd

    随机化选讲的例题 John Doe offered his sister Jane Doe find the gcd of some set of numbers a. Gcd is a positi ...

  4. SAP后台JOB的Submit & EVENT JOB

    SM35执行一个后台作业后,想及时停止, 运行SM37后,点击ctr + F1停止活动的作业,系统根本就没反应. 解决方法: 第一步:SM50, 找到,Ty.列为BGD的(Background),然后 ...

  5. <html5 canvas>一个简单的矩形

    Html5: <!doctype html> <html> <head> <meta charset="UTF-8"> <ti ...

  6. jmeter XML格式的结果中各属性的含义

    最近在搞jmeter,生成xml的测试报告,对报告字段进行解释,可能是自己不会找,网上资源不多,好不容易找到的,记录下来: 感谢博主:http://blog.163.com/zhang_jing/bl ...

  7. 利用本地SQL Server维护计划来维护SQL Database

    On-Premise的SQL Server提供了维护计划来定期.定时的维护SQL Server.一般的做法是:定义SQL Server Agent Jobs,而后维护计划帮助我们定期.定时执行SQL ...

  8. Helloworld 在jvm 内存图

    HelloWorld.java源码如下:   public class HelloWorld { public static void main(String[] args) { String s ; ...

  9. jxl教程图文详解

    近来学习了下jxl的操作Excel报表功能,现有的API基本可以满足当前的需要,抽空做了一个学生成绩查询报表的例子. 先看效果图: 从图中可以看到这是一个交叉报表,横向到Q列,纵向有22行,全部是通过 ...

  10. Careercup - Microsoft面试题 - 23123665

    2014-05-12 07:44 题目链接 原题: Given an array having unique integers, each lying within the range <x&l ...