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 ...
随机推荐
- mysql之调优概论
一 简介 咱们先不说cpu的频率,内存的大小(这个和索引一样重要,但不是本文讨论的内容),硬盘的寻道时间.想起mysql的调优,最起码的必须知道explain执行计划,慢sql日志,老旧的profi ...
- [转]ECMAScript 6 入门 -编程风格
本文转自:http://es6.ruanyifeng.com/#docs/style 编程风格 块级作用域 字符串 解构赋值 对象 数组 函数 Map结构 Class 模块 ESLint的使用 本章探 ...
- C Primer Plus note6
error: invalid preprocessing directive #difine| 无效的宏定义处理 宏定义define 写成了 difine.
- unity3d之实现各种滑动效果
一. 点击滑动页面 新建了一个带mask的prefab,加上代码只需要将图片prefab.按钮prefab和所想添加的图片 拖进去会自动生成按钮,滑动速度可以随意调time,滑动效果用itween实现 ...
- mysql中的find_in_set的使用
原文 http://www.php-note.com/article/detail/383 举个例子来说: 有个文章表里面有个type字段,它存储的是文章类型,有 1头条.2推荐.3热点.4图文... ...
- 动态设置热区coords的坐标
window.onresize = adjuest; function adjuest(){ var picw = $(".imgbox img").width(); var pi ...
- CSS之inline和inline-block
inline-block 控制台-代码: PS:inline-block是让元素以内联形式存在,也就是不是块级,但是表现起来(又具有块级元素的高度)--也就是可以调高度(margin或者padding ...
- 模块—— 序列化模块、random模块、os模块 、 sys模块、hashlib模块、collections模块
今天我们来说说Python中的模块: 第三方模块 可以下载/安装/使用 第一步:将pip.exe 所在的目录添加到环境变量中第二步:输入pip第三步:pip install 要安装的模块名称 #pi ...
- (转)快速了解微信小程序的使用,一个根据小程序的框架开发的todos app
微信官方已经开放微信小程序的官方文档和开发者工具.前两天都是在看相关的新闻来了解小程序该如何开发,这两天官方的文档出来之后,赶紧翻看了几眼,重点了解了一下文档中框架与组件这两个部分,然后根据简易教程, ...
- js内存空间详细图解-笔记
原文参考http://mp.weixin.qq.com/s/NGqdjhoU3MR9LD0yH6tKIw 栈-先进后出堆-类比成书于书架(形象),只要知道Key就可以找到value 基础数据类型(Un ...