【BZOJ3999】旅游,树链剖分中的有向信息合并
Time:2016.05.26
Author:xiaoyimi
转载注明出处谢谢
传送门
思路:
(调了好久发现是链剖打错了)
线性版本的话可以去看水果姐逛水果店Ⅰ
这个放到了树上,还加了个修改操作
先链剖,再维护最大值及最小值,左->右最大差值,右->左最大差值
区间修改打标记
线段树上的连续区间维护起来很好办
关键就在于怎么维护询问中访问的所有链的信息
之前没有写过类似这样的,向char哥学习了一下,具体就是线段树查询时返回线段树的数据类型的节点,来存储和维护信息。
细节信息个人推荐看代码
注意:
很容易把左右,大小,深浅这些东西搞混了……最后就不知所措= =
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#define M 50003
#define inf 0x7ffffff
using namespace std;
int n,q,tot,cnt;
int w[M],fa[M],son[M],siz[M],top[M],dep[M],L[M],pre[M],first[M],lazy[M<<2];
struct edge{int v,next;}e[M<<1];
struct seg
{int sum_L,sum_R,maxn,minn;//sum_L->由深到浅(线段树区间由大到小走),sum_R->由浅到深(线段树区间由小到大)
}tree[M<<2];
seg Null={-inf,-inf,-inf,inf};
int in()
{int t=0;char ch=getchar();bool f=0;while (!isdigit(ch)) f=(ch=='-'),ch=getchar();while (isdigit(ch)) t=(t<<1)+(t<<3)+ch-48,ch=getchar();return f?-t:t;
}
void add(int x,int y)
{e[++tot]=(edge){y,first[x]};first[x]=tot;e[++tot]=(edge){x,first[y]};first[y]=tot;
}
void dfs1(int x)
{siz[x]=1;for (int i=first[x];i;i=e[i].next)if (e[i].v!=fa[x])fa[e[i].v]=x,dep[e[i].v]=dep[x]+1,dfs1(e[i].v),siz[x]+=siz[e[i].v],son[x]=(siz[son[x]]>siz[e[i].v]?son[x]:e[i].v);
}
void dfs2(int x,int tp)
{L[x]=++cnt;pre[cnt]=x;top[x]=tp;if (son[x]) dfs2(son[x],tp);else return;for (int i=first[x];i;i=e[i].next)if (e[i].v!=fa[x]&&e[i].v!=son[x]) dfs2(e[i].v,e[i].v);
}
void pushup(int now)
{tree[now].maxn=max(tree[now<<1].maxn,tree[now<<1|1].maxn);tree[now].minn=min(tree[now<<1].minn,tree[now<<1|1].minn);tree[now].sum_L=max(tree[now<<1].maxn-tree[now<<1|1].minn,max(tree[now<<1].sum_L,tree[now<<1|1].sum_L));tree[now].sum_R=max(tree[now<<1|1].maxn-tree[now<<1].minn,max(tree[now<<1].sum_R,tree[now<<1|1].sum_R));
}
void pushdown(int now)
{if (!lazy[now]) return;tree[now<<1].maxn+=lazy[now]; tree[now<<1].minn+=lazy[now];lazy[now<<1]+=lazy[now]; lazy[now<<1|1]+=lazy[now];tree[now<<1|1].maxn+=lazy[now];tree[now<<1|1].minn+=lazy[now];lazy[now]=0;
}
void build(int now,int begin,int end)
{if (begin==end){tree[now]=(seg){0,0,w[pre[end]],w[pre[end]]};return;}int mid=begin+end>>1;build(now<<1,begin,mid);build(now<<1|1,mid+1,end);pushup(now);
}
void update(int now,int begin,int end,int l,int r,int val)
{if (l<=begin&&end<=r){lazy[now]+=val;tree[now].maxn+=val;tree[now].minn+=val;return;}pushdown(now);int mid=begin+end>>1;if (mid>=l) update(now<<1,begin,mid,l,r,val);if (mid<r) update(now<<1|1,mid+1,end,l,r,val);pushup(now);
}
seg get(int now,int begin,int end,int l,int r)
{if (l<=begin&&end<=r) return tree[now];pushdown(now);int mid=begin+end>>1;if (mid>=r)return get(now<<1,begin,mid,l,r);else if (mid<l)return get(now<<1|1,mid+1,end,l,r);seg ans,t1=get(now<<1,begin,mid,l,r),t2=get(now<<1|1,mid+1,end,l,r);ans.maxn=max(t1.maxn,t2.maxn);ans.minn=min(t1.minn,t2.minn);ans.sum_L=max(max(t1.sum_L,t2.sum_L),t1.maxn-t2.minn);ans.sum_R=max(max(t1.sum_R,t2.sum_R),t2.maxn-t1.minn);return ans;
}
main()
{n=in();for (int i=1;i<=n;i++) w[i]=in();for (int i=1;i<n;i++) add(in(),in());dfs1(1);dfs2(1,1);build(1,1,n);q=in();int x,y,z;while (q--){x=in();y=in();z=in();seg ans_L=Null,ans_R=Null,t;for (int f1=top[x],f2=top[y];f1!=f2;){if (dep[f1]<dep[f2])t=get(1,1,n,L[f2],L[y]),ans_R.sum_R=max(max(ans_R.sum_R,t.sum_R),ans_R.maxn-t.minn),ans_R.maxn=max(ans_R.maxn,t.maxn),ans_R.minn=min(ans_R.minn,t.minn),update(1,1,n,L[f2],L[y],z),y=fa[f2],f2=top[y];elset=get(1,1,n,L[f1],L[x]),ans_L.sum_L=max(max(ans_L.sum_L,t.sum_L),t.maxn-ans_L.minn),ans_L.maxn=max(ans_L.maxn,t.maxn),ans_L.minn=min(ans_L.minn,t.minn),update(1,1,n,L[f1],L[x],z),x=fa[f1],f1=top[x];}if (dep[x]<=dep[y])t=get(1,1,n,L[x],L[y]),ans_R.sum_R=max(max(ans_R.sum_R,t.sum_R),ans_R.maxn-t.minn),ans_R.maxn=max(ans_R.maxn,t.maxn),ans_R.minn=min(ans_R.minn,t.minn),update(1,1,n,L[x],L[y],z);elset=get(1,1,n,L[y],L[x]),ans_L.sum_L=max(max(ans_L.sum_L,t.sum_L),t.maxn-ans_L.minn),ans_L.maxn=max(ans_L.maxn,t.maxn),ans_L.minn=min(ans_L.minn,t.minn),update(1,1,n,L[y],L[x],z);printf("%d\n",max(ans_R.maxn-ans_L.minn,max(ans_L.sum_L,ans_R.sum_R)));}
}
【BZOJ3999】旅游,树链剖分中的有向信息合并相关推荐
- P1505 [国家集训队]旅游 树链剖分
题目链接 题意:树上更新某一点权值,更新两点简单路径权值,查询最大,最小,和 思路:思路应该比较简单,就是树链剖分后用线段树维护区间最大最小以及区间和. 但是本题比较特殊的是给的边权,转化为点权即可. ...
- 树链剖分中的重链剖分
更多文章可以在本人的个人小站:https://kaiserwilheim.github.io 查看. 转载请注明出处. 引言 树链剖分(简称"树剖",又称"重链剖分&qu ...
- 蒟蒻浅谈树链剖分之一——两个dfs操作
树链剖分,顾名思义就是将树形的结构剖分成链,我们以此便于在链上操作 首先我们需要明白在树链剖分中的一些概念 重儿子:某节点所有儿子中子树最多的儿子 重链:有重儿子构成的链 dfs序:按重儿子优先遍历时 ...
- BZOJ 2243 染色(树链剖分好题)
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 7971 Solved: 2990 [Submit][Stat ...
- HDU 3966 POJ 3237 HYSBZ 2243 HRBUST 2064 树链剖分
树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...
- 【树链剖分】Disruption P(luogu 4374)
正题 luogu 4374 题目大意 给你一棵树,还有若干边,每条边有一定代价,问你删掉树中的每条边后,使其成为连通图的最小代价 解题思路 不难发现,一条边只对两个端点在树中的路径上的边有贡献(即删去 ...
- ⌈洛谷1505⌋⌈BZOJ2157⌋⌈国家集训队⌋旅游【树链剖分】
题目链接 [洛谷] [BZOJ] 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T ...
- BZOJ 2157 「国家集训队」旅游(树链剖分,线段树,边权转点权)【BZOJ计划】
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2157 是 hydro 的 BZOJ ...
- bzoj 3999: [TJOI2015]旅游(树链剖分)
3999: [TJOI2015]旅游 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 423 Solved: 214 [Submit][Status ...
最新文章
- android 多种特效TextView
- 2.3线性表的链式存储和运算—双向链表
- 嘉楠勘智 K210 RISC-V 64位双核处理器开发板(荔枝丹)
- 微软将弃用 System.Data.OracleClient
- ArcGIS中通过JPG图片文件提取矢量要素
- 如何修复rpc服务器,打印时弹出RPC服务器不可用修复教程
- android ppt的动画效果怎么做,Android 仿 PPT 进入动画效果合集
- 金色传说:SAP-ABAP-销售订单增强:记录销售订单修改信息和修改原因
- 文科生学计算机能考研吗,求推荐文科生可以跨考计算机的名校
- 《游戏机制——高级游戏设计技术》一1.1 规则定义游戏
- JAVA的诞生及版本
- 【谷歌地图--MapsSDK集成】
- jvm基础学习总结笔记
- 燕山大学课程实践项目报告:ISBN号识别系统的设计与开发
- ajaxsubmit php上传文件,怎样用AjaxSubmit()提交file文件
- 用Python搭建一个股票舆情分析系统
- java序列化,从底层到序列化所隐藏的问题以及解决方案
- 中心极限定理和泊松分布的条件
- 使用librosa进行语音情感识别
- 国密SM9算法C++实现之六:密钥封装解封算法
热门文章
- 开源大数据平台HBase对接OBS操作指南
- 【华为云实战开发】2.Docker镜像部署怎么玩才酷炫?
- php二分法 冒泡 快速排序,PHP 常见算法【冒泡排序, 快速排序, 插入排序, 取舍排序, 二分法查找, .】...
- Spark内核解析2
- Hadoop简介与分布式安装
- WORD如何隐藏选中内容?
- python函数定义时参数相当于占位符_python中函数的参数
- java 异常处理线程_转:Java子线程中的异常处理(通用)
- project不显示里程碑标志_3万台!纽荷兰大方捆打捆机再创全新里程碑
- 软件测试常见笔试面试题(一)