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. 在myeclipse中换项目的jdk版本,你需要做哪些?

    首先,我们必须把jdk在系统中安装好,环境变量配好,才能进行下一步的操作…… 然后在点击项目,右键选择Properties,找到Java Build Path,拉倒最下面,把原来的jdk版本给remo ...

  2. Mysql插入Emoji表情出错

    Caused by: java.sql.SQLException: Incorrect at com.mysql.jdbc.SQLError.createSQLException(SQLError.j ...

  3. 【Hadoop系列】linux下 root用户免密码登录远程主机 ssh

    SSH原理:[Hadoop系列]linux SSH原理解析 操作环境: CentOS 6.5 操作对象: 用户A主机和远程主机B 正文部分:斜体加粗代表linux指令. linux下 非root用户免 ...

  4. 关于request请求的基本获取

      1.Request对象的作用是与客户端交互,收集客户端的Form.Cookies.超链接,或者收集服务器端的环境变量. request对象是从客户端向服务器发出请求,包括用户提交的信息以及客户端的 ...

  5. 微信公众号开发《一》OAuth2.0网页授权认证获取用户的详细信息,实现自动登陆

    原创声明:本文为本人原创作品,绝非他处转账,转载请联系博主 从接触公众号到现在,开发维护了2个公众号,开发过程中遇到很多问题,现在把部分模块功能在这备案一下,做个总结也希望能给其他人帮助 工欲善其事, ...

  6. Java 之数组(4)

    什么是数组: 问:编写代码保存 4 名学生的考试成绩. 答:简单啊,定义 4 个变量呗 问:那“计算全年级 400 名学生的考试成绩”,肿么办 答: ....... 数组,就可以帮助你妥妥的解决问题啦 ...

  7. vs2010开发activex(MFC)控件/ie插件(二):js传参数

    原文:http://blog.csdn.net/yhhyhhyhhyhh/article/details/50802075  js传参数给activex控件. 过程为:js变量通过activex类的属 ...

  8. python RabbitMQ广播

    消息公平分发 如果Rabbit只管按顺序把消息发到各个消费者身上,不考虑消费者负载的话,很可能出现,一个机器配置不高的消费者那里堆积了很多消息处理不完,同时配置高的消费者却一直很轻松.为解决此问题,可 ...

  9. Django_MTV模型

    创建DJango项目过程: 1:安装Django包 方式一:pip3 install django 方式二:pycharm-->file--->settings-->找到projec ...

  10. 微信小程序scroll-view隐藏滚动条方法

    在wxss里加入以下代码: ::-webkit-scrollbar{ width: 0; height: 0; color: transparent; }   源链接:https://blog.csd ...