BZOJ3999 [TJOI2015]旅游 【树剖 + 线段树】
题目
为了提高智商,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]旅游 【树剖 + 线段树】的更多相关文章
- BZOJ_2157_旅游_树剖+线段树
BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...
- BZOJ_2238_Mst_树剖+线段树
BZOJ_2238_Mst_树剖+线段树 Description 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影 ...
- BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树
BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树 Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为 ...
- 【BZOJ5210】最大连通子块和 树剖线段树+动态DP
[BZOJ5210]最大连通子块和 Description 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块 ...
- [LNOI2014]LCA(树剖+线段树)
\(\%\%\% Fading\) 此题是他第一道黑题(我的第一道黑题是蒲公英) 一直不敢开,后来发现是差分一下,将询问离线,树剖+线段树维护即可 \(Code\ Below:\) #include ...
- [CF1007D]Ants[2-SAT+树剖+线段树优化建图]
题意 我们用路径 \((u, v)\) 表示一棵树上从结点 \(u\) 到结点 \(v\) 的最短路径. 给定一棵由 \(n\) 个结点构成的树.你需要用 \(m\) 种不同的颜色为这棵树的树边染色, ...
- LOJ#3088. 「GXOI / GZOI2019」旧词(树剖+线段树)
题面 传送门 题解 先考虑\(k=1\)的情况,我们可以离线处理,从小到大对于每一个\(i\),令\(1\)到\(i\)的路径上每个节点权值增加\(1\),然后对于所有\(x=i\)的询问查一下\(y ...
- BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)
传送门 完了今天才知道原来线段树的动态开点和主席树是不一样的啊 我们先考虑没有宗教信仰的限制,那么就是一个很明显的树剖+线段树,路径查询最大值以及路径和 然后有了宗教信仰的限制该怎么做呢? 先考虑暴力 ...
- 【bzoj4699】树上的最短路(树剖+线段树优化建图)
题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...
- 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 ...
随机推荐
- python setup.py install 报错
python setup.py install 报错信息 [root@VM_25_28_centos psutil-2.0.0]# python setup.py install running in ...
- 【wiki】红帽linux
Red Hat Enterprise Linux From Wikipedia, the free encyclopedia wiki 上面红帽的版本信息. https://en.wikipedia. ...
- 查看电脑是否安装node.js
打开命令行
- WPF中批量进行验证操作
//ref,out private void CheckTextboxNotEmpty(ref bool isOK, params TextBox[] textboxes) { foreach (Te ...
- 关于Runtime Issues
前言:在使用某移动直播的SDK的时候发现,在Run应用的时候会有紫色的警告(Xcode9 + iOS11) 当时还专门提交了工单,当时对方的回复是,大概意思是不影响使用,后期修复. 今天看视频发现这是 ...
- 微信小程序的开发——01小程序的执行流程是怎样的?
作者:叶小钗 转载至:https://www.cnblogs.com/yexiaochai/p/9346043.html 我们这边最近一直在做基础服务,这一切都是为了完善技术体系,这里对于前端来说便是 ...
- P4746 C’s problem(c)
时间: 1000ms / 空间: 655360KiB / Java类名: Main 背景 冬令营入学测试 描述 题目描述 小C是一名数学家,由于它自制力比较差,经常通宵研究数学问题. 这次它因为这个数 ...
- 十七、MySQL UNION 操作符
MySQL UNION 操作符 本教程为大家介绍 MySQL UNION 操作符的语法和实例. 描述 MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中.多 ...
- javascript的基本类型和引用类型
一.基本类型和引用类型 基本的数据类型有5个:undefined,boolean,number,string,null ? 1 2 3 4 5 typeof null; //"object& ...
- ELK详细安装部署
一.前言 日志主要包括系统日志和应用程序日志,运维和开发人员可以通过日志了解服务器中软硬件的信息,检查应用程序或系统的故障,了解故障出现的原因,以便解决问题.分析日志可以更清楚的了解服务器的状态和 ...