BZOJ3999:[TJOI2015]旅游(树链剖分)
Description
Input
Output
对于每次询问,输出ZJY可能获得的最大利润,如果亏本则输出0。
Sample Input
1 2 3
1 2
2 3
2
1 2 100
1 3 100
Sample Output
1
Solution
对拍+debug使我快乐
一开始把题给读错了……

然后就很容易想到用树链剖分维护。
不过这个是有限制的,即在路径上,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]旅游(树链剖分)的更多相关文章
- BZOJ 2157: 旅游( 树链剖分 )
树链剖分.. 样例太大了根本没法调...顺便把数据生成器放上来 -------------------------------------------------------------------- ...
- BZOJ2157旅游——树链剖分+线段树
题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路 ...
- BZOJ2157: 旅游 树链剖分 线段树
http://www.lydsy.com/JudgeOnline/problem.php?id=2157 在对树中数据进行改动的时候需要很多pushdown(具体操作见代码),不然会wa,大概原因 ...
- BZOJ 2157: 旅游 (树链剖分+线段树)
树链剖分后线段树维护区间最大最小值与和. 支持单点修改与区间取反. 直接写个区间取反标记就行了.线段树板题.(200行6000B+ 1A警告) #include <cstdio> #inc ...
- 【BZOJ2157】旅游 树链剖分+线段树
[BZOJ2157]旅游 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本 ...
- 洛谷 P1505 [国家集训队]旅游 树链剖分
目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 思路 AC代码 总结 题面 题目链接 P1505 [国家集训队]旅游 题目描述 Ray 乐 ...
- LG1505 [国家集训队]旅游 树链剖分
问题描述 LG1505 题解 边化点权. 超级多操作的树剖板子... 以后就拿这个当树剖板子复习吧... \(\mathrm{Code}\) #include<bits/stdc++.h> ...
- [BZOJ2157]旅游(树链剖分/LCT)
树剖裸题,当然LCT也可以. 树剖: #include<cstdio> #include<algorithm> #define ls (x<<1) #define ...
- LUOGU P1505 [国家集训队]旅游 (树链剖分+线段树)
传送门 解题思路 快被调死的码农题,,,其实就是一个边权下放到点权的线段树+树剖. #include<iostream> #include<cstdio> #include&l ...
随机推荐
- 架构实战项目心得(十):基于spring-ladp的统一用户中心结构设计以及代码结构设计
一.目录设计 1 公司 2 部门 3 注册人员 4 层级人员 二.规则 1 注册 自行注册人员放到模拟公司的目录下,等所属公司组织结构建立完毕,将此人员迁移到所属公司(或者删除此人员,所属公司新建此人 ...
- Laravel 使用Voyager导致多个数据库连接总是返回默认连接?
问题与分析 最近的项目碰到一个奇怪的问题,在Laravel(5.3)中想建立多个数据库连接连到MySQL的不同数据库(另一个连接名为conn2),执行如下语句得到却发现得到的仍然是默认连接: $con ...
- thinkjs crud练习
今天看了下thinkjs(v2.1.7),做了一个简单的入门demo,基于mysql数据库增删改查,详细源码如下: 页面整体展示: 会员新增: 删除: 查询: 主页面: <!DOCTYPE ht ...
- 第6章 征服CSS3选择器(上)
属性选择器 在HTML中,通过各种各样的属性可以给元素增加很多附加的信息.例如,通过id属性可以将不同div元素进行区分. 在CSS2中引入了一些属性选择器,而CSS3在CSS2的基础上对属性选择器进 ...
- 【代码笔记】Java常识性基础补充(二)——数组、ArrayList集合、ASCII编码、 eclipse基础操作、eclipse调试、eclipse项目导入、eclipse快捷键
1.0 如何定义数组以及访问数组中的元素,如下所示.ArrayDemo01.java public class ArrayDemo01 { public static void main(String ...
- Python基础-列表生成式和生成器表达式
一.列表生成式(List Comprehension) 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式. 举个例子,要生成list ...
- CentOS 7运维管理笔记(12)----GUI配置工具Webmin的安装
早期的Linux系统管理员或是Web管理员在修改服务器配置时使用最多的就是vi编辑器,但是现在越来越多的基于GUI界面的配置工具出现了,毕竟人们还是喜欢以直接的可视化的方式来修改服务器的配置,而不是再 ...
- SpringBoot开发(改变环境属性、读取资源文件、Bean 配置、模版渲染、profile 配置)
1.概念 SpringBoot 开发深入 2.具体内容 在之前已经基本上了解了整个 SpringBoot 运行机制,但是也需要清楚的认识到以下的问题,在实际的项目开发之中,尤其是 Java 的 MVC ...
- c/c++ 按照行读取文件
本文代码都在Windows/VC++6.0下测试过, 在linux/g++下也没有问题. 但是请一定注意linux和Windows文件格式的区别,比如: 1. 当linux上的代码读取Windows文 ...
- 如何修改settings.xml的镜像
今天在下载一个maven依赖包时候,下载后一直显示的是upload的jar包,然后检查了下自己的settings.xml配置,发现依赖的还是以前的内网nexus得配置.所以下载不下来,现在改为ali的 ...