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 ...
随机推荐
- cs端调用webApi
public class Httphelper { public static string Post1(string url, string postString) { using (WebClie ...
- Firebird 用查询结果集更新数据,merge
Merge语法: MERGE INTO target [[AS] target-alias ] USING source [[AS] source-alias ] ON join-condition ...
- [转]Using $select, $expand, and $value in ASP.NET Web API 2 OData
本文转自:https://docs.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/using- ...
- 1.Windows服务-->添加一个简单的服务
Windows服务应用程序是一种需要长期运行的应用程序,它对于服务器环境特别适合.它没有用户界面,并且也不会产生任何可视输出.任何用户消息都会被 写进Windows事件日志.计算机启动时,服务会自动开 ...
- Error:All flavors must now belong to a named flavor dimension.
环境 android studio 3.0 错误 Error:All flavors must now belong to a named flavor dimension. 解决 在build.gr ...
- 为什么分布式一定要有redis?(转)
为什么分布式一定要有redis? 程序员小灰 6天前 点击上方“程序员小灰”,选择“置顶公众号” 有趣有内涵的文章第一时间送达! 作者:孤独烟 来自:http://rjzheng.cnblogs.co ...
- jQuery源码分析系列 : 整体架构
query这么多年了分析都写烂了,老早以前就拜读过, 不过这几年都是做移动端,一直御用zepto, 最近抽出点时间把jquery又给扫一遍 我也不会照本宣科的翻译源码,结合自己的实际经验一起拜读吧! ...
- Java读取粘贴板内容
package com.test.jvm.oom.design; import java.awt.Image; import java.awt.Toolkit; import java.awt.dat ...
- 判断sql是否存在特定的对象
1 判断数据库是否存在if exists (select * from sys.databases where name = '数据库名') drop database [数据库名] 2 判断表是否存 ...
- 主动驱动事件执行--createEvent
1. createEvent(eventType)参数:eventType 共5种类型: Events :包括所有的事件. HTMLEvents:包括 'abort', 'b ...