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

不拍一下还真不知道自己错了不少细节
对拍+debug使我快乐
一开始把题给读错了……
对于这个题,我们要做的就是查询路径上的最大差值(max-min)。
然后就很容易想到用树链剖分维护。
不过这个是有限制的,即在路径上,min必须出现在max前面。
怎么办呢?我们可以分两种情况来考虑。
1、max,min出现在一段完整的重链中。这个我们可以用线段树上的标记很好的维护。
维护一个ans1一个ans2,分别表示不同方向时这一段内的最大差值。(看一下pushup函数就懂了)
2、max,min出现在不同的链中
我们往上跳的时候,按顺序记录一下我们路径经过的轻重链的信息。
跳完之后扫一遍更新答案即可。
细节挺多的反正我拍挂了很多次

Code

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define N (50000+100)
using namespace std; struct segt{int val,add,max,min,ans1,ans2;}Segt[N<<],refun[N];
struct node{int to,next;}edge[N<<];
int n,m,a[N],u,v,l,ans;
int head[N],num_edge;
int Father[N],Depth[N],Son[N],Sum[N];
int T_num[N],Tree[N],Top[N],dfs_num;
queue<segt>q[]; void add(int u,int v)
{
edge[++num_edge].to=v;
edge[num_edge].next=head[u];
head[u]=num_edge;
} void Dfs1(int x)
{
Sum[x]=;
Depth[x]=Depth[Father[x]]+;
for (int i=head[x]; i; i=edge[i].next)
if (edge[i].to!=Father[x])
{
Father[edge[i].to]=x;
Dfs1(edge[i].to);
Sum[x]+=Sum[edge[i].to];
if (!Son[x] || Sum[Son[x]]<Sum[edge[i].to])
Son[x]=edge[i].to;
}
} void Dfs2(int x,int pre)
{
T_num[x]=++dfs_num;
Tree[dfs_num]=a[x];
Top[x]=pre;
if (Son[x]) Dfs2(Son[x],pre);
for (int i=head[x]; i; i=edge[i].next)
if (edge[i].to!=Father[x] && edge[i].to!=Son[x])
Dfs2(edge[i].to,edge[i].to);
} void Pushdown(int now,int l,int r)
{
if (Segt[now].add)
{
int mid=(l+r)>>;
Segt[now<<].add+=Segt[now].add;
Segt[now<<].val+=Segt[now].add*(mid-l+);
Segt[now<<|].add+=Segt[now].add;
Segt[now<<|].val+=Segt[now].add*(r-mid);
Segt[now<<].max+=Segt[now].add;
Segt[now<<].min+=Segt[now].add;
Segt[now<<|].max+=Segt[now].add;
Segt[now<<|].min+=Segt[now].add;//一开始max和min忘记更新*%……%&*
Segt[now].add=;
}
} segt Pushup(int x,segt ls,segt rs)//pushup返回类型改一下方便处理
{
segt now=Segt[x];
now.val=ls.val+rs.val;
now.max=max(ls.max,rs.max);
now.min=min(ls.min,rs.min);
now.ans1=max(ls.ans1,rs.ans1);
now.ans1=max(now.ans1,rs.max-ls.min);
now.ans2=max(ls.ans2,rs.ans2);
now.ans2=max(now.ans2,ls.max-rs.min);
return now;
} void Build(int now,int l,int r)
{
if (l==r){Segt[now].val=Segt[now].max=Segt[now].min=Tree[l];return;}
int mid=(l+r)>>;
Build(now<<,l,mid); Build(now<<|,mid+,r);
Segt[now]=Pushup(now,Segt[now<<],Segt[now<<|]);
} void Update(int now,int l,int r,int l1,int r1,int k)
{
if (l>r1 || r<l1) return;
if (l1<=l && r<=r1)
{
Segt[now].val+=(r-l+)*k;
Segt[now].add+=k;
Segt[now].max+=k;
Segt[now].min+=k;
return;
}
Pushdown(now,l,r);
int mid=(l+r)>>;
Update(now<<,l,mid,l1,r1,k);Update(now<<|,mid+,r,l1,r1,k);
Segt[now]=Pushup(now,Segt[now<<],Segt[now<<|]);
} segt Query(int now,int l,int r,int l1,int r1)
{
if (l1<=l && r<=r1)
return Segt[now];
Pushdown(now,l,r);
int mid=(l+r)>>;
if (r1<=mid) return Query(now<<,l,mid,l1,r1);
if (l1>=mid+) return Query(now<<|,mid+,r,l1,r1);
return Pushup(now,Query(now<<,l,mid,l1,r1),Query(now<<|,mid+,r,l1,r1));
} void Change(int x,int y,int k)
{
int fx=Top[x],fy=Top[y];
while (fx!=fy)
{
if (Depth[fx]<Depth[fy])
swap(x,y),swap(fx,fy);
Update(,,n,T_num[fx],T_num[x],k);
x=Father[fx],fx=Top[x];
}
if (Depth[x]<Depth[y]) swap(x,y);
Update(,,n,T_num[y],T_num[x],k);
} int Ask(int x,int y)//主要就是这个函数里的问题,我开了两个queue来记录路径。
{
int fx=Top[x],fy=Top[y];
int now=,ans=,cnt=,h=,sum;
while (fx!=fy)
{
if (Depth[fx]<Depth[fy])
swap(x,y),swap(fx,fy),now^=;
segt no=Query(,,n,T_num[fx],T_num[x]);
q[now].push(no); cnt++;
ans=max(ans,now==?no.ans1:no.ans2);
x=Father[fx],fx=Top[x];
}
if (Depth[x]<Depth[y]) swap(x,y),now^=;
segt no=Query(,,n,T_num[y],T_num[x]);
ans=max(ans,now==?no.ans1:no.ans2);
q[now].push(no); cnt++;
sum=cnt; while (!q[].empty()) refun[++h]=q[].front(),q[].pop();
while (!q[].empty()) refun[cnt--]=q[].front(),q[].pop();
int minn=refun[].min;
for (int i=; i<=sum; ++i)//扫一遍路径上的链,然后更新一下。
{
ans=max(ans,refun[i].max-minn);
minn=min(minn,refun[i].min);//一开始这里忘了更新了#¥%#¥*&
}
return ans;
} int main()
{
scanf("%d",&n);
for (int i=; i<=n; ++i)
scanf("%d",&a[i]);
for (int i=; i<=n-; ++i)
{
scanf("%d%d",&u,&v);
add(u,v); add(v,u);
}
Dfs1(); Dfs2(,);
Build(,,n);
scanf("%d",&m);
for (int i=; i<=m; ++i)
{
scanf("%d%d%d",&u,&v,&l);
int ans=Ask(u,v);
printf("%d\n",ans>?ans:);
Change(u,v,l);
}
}

BZOJ3999:[TJOI2015]旅游(树链剖分)的更多相关文章

  1. BZOJ 2157: 旅游( 树链剖分 )

    树链剖分.. 样例太大了根本没法调...顺便把数据生成器放上来 -------------------------------------------------------------------- ...

  2. BZOJ2157旅游——树链剖分+线段树

    题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路 ...

  3. BZOJ2157: 旅游 树链剖分 线段树

    http://www.lydsy.com/JudgeOnline/problem.php?id=2157   在对树中数据进行改动的时候需要很多pushdown(具体操作见代码),不然会wa,大概原因 ...

  4. BZOJ 2157: 旅游 (树链剖分+线段树)

    树链剖分后线段树维护区间最大最小值与和. 支持单点修改与区间取反. 直接写个区间取反标记就行了.线段树板题.(200行6000B+ 1A警告) #include <cstdio> #inc ...

  5. 【BZOJ2157】旅游 树链剖分+线段树

    [BZOJ2157]旅游 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本 ...

  6. 洛谷 P1505 [国家集训队]旅游 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 思路 AC代码 总结 题面 题目链接 P1505 [国家集训队]旅游 题目描述 Ray 乐 ...

  7. LG1505 [国家集训队]旅游 树链剖分

    问题描述 LG1505 题解 边化点权. 超级多操作的树剖板子... 以后就拿这个当树剖板子复习吧... \(\mathrm{Code}\) #include<bits/stdc++.h> ...

  8. [BZOJ2157]旅游(树链剖分/LCT)

    树剖裸题,当然LCT也可以. 树剖: #include<cstdio> #include<algorithm> #define ls (x<<1) #define ...

  9. LUOGU P1505 [国家集训队]旅游 (树链剖分+线段树)

    传送门 解题思路 快被调死的码农题,,,其实就是一个边权下放到点权的线段树+树剖. #include<iostream> #include<cstdio> #include&l ...

随机推荐

  1. php.ini配置max_execution_time和FPM配置request_terminate_timeout

    PHP限定脚本执行时长的方式有几种,下面说下php.ini中的max_execution_time和php-fpm.conf中的request_terminate_timeout 1. php.ini ...

  2. wms-ssv数据字典

    --------------------------------------------以下,托盘-- dbo.Container --托盘 , "托盘状态", "Con ...

  3. SQL Server修改表结构,不允许保存更改。

    当修改表结构时,sql server会弹出对话框,显示以下内容: 不允许保存更改.您所做的更改要求删除并重新创建以下表.您对无法重新创建的表进行了更改或者启用了“阻止保存要求重新创建表的更改”选项. ...

  4. 三、thymeleaf的使用

    1.简介 thymleaf是一个基于html的页面模板,springboot极力推荐使用它,代替jsp. API地址:https://www.thymeleaf.org/doc/tutorials/3 ...

  5. JAVA_SE_Day02 String 的正则表达式

    字符串支持正则表达式的方法一: boolean matches(String regex) 注意: 给定的正则表达式就算不指定边界符(^,$),也会全匹配验证 空字符串和null 空字符串是看不见,而 ...

  6. shell输入与输出功能

    一.shell输入功能 1. 2. 二.shell输出功能 1.字符界面前景颜色 2.字符界面背景颜色 3.其他输出命令 ①cat 输出文本,将文本的格式也输出 ②tee 既输出,也保存到文件里 ③m ...

  7. Spring课程 Spring入门篇 6-1 Spring AOP API的PointCut、advice的概念及应用

    本节主要是模拟spring aop 的过程. 实现spring aop的过程 这一节老师虽然说是以后在工作中不常用这些api,实际上了解还是有好处的, 我们可以从中模拟一下spring aop的过程. ...

  8. 一道google的面试题(据说)

    1. 原题(同事给的) Max Howell 参加了谷歌的面试,出题人竟然要求 Max Howell 在白板上作出解答,Max Howell 当然愤怒地拒绝了,回家以后马上在微博上跟我们分享他的吐槽: ...

  9. vue-构建项目相关事项

    安装 :vue-cli npm install -g vue-cli 使用webpack 打包 vue 項目的創建: vue init webpack 項目名子 生產基本的項目結構后 進入到項目目錄 ...

  10. iview table数据排序不正确

    在使用iview的table组件时,要做排序 代码: sortable: true,sortMethod: (a, b, type) => { if (type === 'desc') { re ...