bzoj 3999: [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
HINT
Source
省选前写的没发
题意:给定一个有nn个节点的树,每个点又点权vivi,每次选取一条树链[a,b],求出max(vj−vi),其中i,j∈[a,b]i,j∈[a,b]且i出现在j前面,最后树链[a,b][a,b]上的点点权都加上v′
显然的链剖转为序列问题,但线段树打起来太操蛋了,所以我选择了打分块;
由于要满足i出现在j的前面,所以我们必须按照路径的顺序来处理,所以跳lca的时候要把路径存下来,并且终点到lca的路径要逆序处理,所以代码很冗长。
具体做法的话就是:
对于路径按顺序一直维护一个最小值,由于按照顺序处理,所以保证了i在j前面
对于散点就直接与最小值做差比较,并更新最小值
对于整块,就为维护一个整块内的最大值,最小值,和这一个块单独能产生的最大贡献;
获益的话再与(最大值-不算这个块的最小值)和(这个块的单独贡献)取max;
然后用块内最小值更新最小值
更改暴力重构即可
nlog*sqrt(n);卡时过的
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define int long long
using namespace std;
const int N=200050;
const int Inf=(1ll<<60);
int gi(){
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
int cnt,head[N],to[N],nxt[N],top[N],son[N],size[N],fa[N],deep[N],dfn[N],id[N],ed[N],v[N];
int block,pos[N],L[N],R[N],MAX[N],MIN[N],MAXV[N],tot,tot2,tt,sum,add[N];
int MAX2[N],MIN2[N],MAXV2[N];
int minn,maxv;
struct data{
int l,r;
}q[N],q2[N];
bool cmp1(data a,data b){return a.r>b.r;}
bool cmp2(data a,data b){return a.r<b.r;}
inline int Min(int a,int b){
return a<b?a:b;
} inline int Max(int a,int b){
return a>b?a:b;
}
inline void dfs1(RG int x,RG int f){
deep[x]=deep[f]+1;size[x]=1;
for(RG int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y!=f){
fa[y]=x;dfs1(y,x);
size[x]+=size[y];
if(size[y]>size[son[x]]) son[x]=y;
}
}
}
inline void dfs2(RG int x,RG int f){
dfn[x]=++sum;id[sum]=x;top[x]=f;
if(son[x]) dfs2(son[x],f);
for(RG int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y!=fa[x]&&y!=son[x]) dfs2(y,y);
}
}
inline int lca(RG int x,RG int y){
tot=0;int fl=1;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]]) swap(x,y),fl^=1;
if(fl) q[++tot]=(data){dfn[top[x]],dfn[x]};
else q2[++tot2]=(data){dfn[top[x]],dfn[x]};
x=fa[top[x]];
}
if(deep[x]<deep[y]) swap(x,y),fl^=1;
if(fl) q[++tot]=(data){dfn[y],dfn[x]};
else q2[++tot2]=(data){dfn[y],dfn[x]};
return y;
}
inline void lnk(RG int x,RG int y){
to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt;
to[++cnt]=x,nxt[cnt]=head[y],head[y]=cnt;
}
inline void rebuild(RG int i){
MAX[i]=v[id[L[i]]],MIN[i]=v[id[L[i]]],MAXV[i]=0;
for(RG int j=L[i]+1;j<=R[i];j++){
MAXV[i]=Max(MAXV[i],v[id[j]]-MIN[i]);
MAX[i]=Max(MAX[i],v[id[j]]);MIN[i]=Min(MIN[i],v[id[j]]);
}
MAX2[i]=MAX[i],MIN2[i]=v[id[R[i]]],MAXV2[i]=0;
for(RG int j=R[i]-1;j>=L[i];j--){
MAXV2[i]=Max(MAXV2[i],v[id[j]]-MIN2[i]);
MIN2[i]=Min(MIN2[i],v[id[j]]);
}
}
inline void update(RG int l,RG int r,RG int c){
if(pos[l]==pos[r]){
for(int i=l;i<=r;i++) v[id[i]]+=c;
rebuild(pos[l]);
}
else{
for(RG int i=l;i<=R[pos[l]];i++) v[id[i]]+=c;
rebuild(pos[l]);
for(RG int i=pos[l]+1;i<=pos[r]-1;i++) add[i]+=c;
for(RG int i=L[pos[r]];i<=r;i++) v[id[i]]+=c;
rebuild(pos[r]);
}
}
inline void query(RG int l,RG int r){
if(pos[l]==pos[r]){
for(RG int i=l;i<=r;i++){
maxv=Max(maxv,v[id[i]]+add[pos[l]]-minn);
minn=Min(minn,v[id[i]]+add[pos[l]]);
}
}
else{
for(RG int i=l;i<=R[pos[l]];i++){
maxv=Max(maxv,v[id[i]]+add[pos[l]]-minn);
minn=Min(minn,v[id[i]]+add[pos[l]]);
}
for(RG int i=pos[l]+1;i<=pos[r]-1;i++){
maxv=Max(maxv,max(MAX[i]+add[i]-minn,MAXV[i]));
minn=Min(minn,MIN[i]+add[i]);
}
for(RG int i=L[pos[r]];i<=r;i++){
maxv=Max(maxv,v[id[i]]+add[pos[r]]-minn);
minn=Min(minn,v[id[i]]+add[pos[r]]);
}
}
}
inline void query2(RG int r,RG int l){
if(pos[l]==pos[r]){
for(RG int i=r;i>=l;i--){
maxv=Max(maxv,v[id[i]]+add[pos[l]]-minn);
minn=Min(minn,v[id[i]]+add[pos[l]]);
}
}
else{
for(RG int i=r;i>=L[pos[r]];i--){
maxv=Max(maxv,v[id[i]]+add[pos[r]]-minn);
minn=Min(minn,v[id[i]]+add[pos[r]]);
}
for(RG int i=pos[r]-1;i>=pos[l]+1;i--){
maxv=Max(maxv,Max(MAX2[i]+add[i]-minn,MAXV2[i]));
minn=Min(minn,MIN2[i]+add[i]);
}
for(RG int i=R[pos[l]];i>=l;i--){
maxv=Max(maxv,v[id[i]]+add[pos[l]]-minn);
minn=Min(minn,v[id[i]]+add[pos[l]]);
}
}
}
main()
{
int n=gi();for(int i=1;i<=n;i++) v[i]=gi();
for(RG int i=1;i<n;i++){
int x=gi(),y=gi();lnk(x,y);
}
dfs1(1,0);dfs2(1,1);
block=sqrt(n);sum=n/block;
if(n%block) sum++;
for(RG int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
for(RG int i=1;i<=sum;i++) L[i]=(i-1)*block+1,R[i]=i*block;
R[sum]=n;
for(RG int i=1;i<=sum;i++){
MAX[i]=v[id[L[i]]],MIN[i]=v[id[L[i]]];
for(RG int j=L[i]+1;j<=R[i];j++){
MAXV[i]=Max(MAXV[i],v[id[j]]-MIN[i]);
MAX[i]=Max(MAX[i],v[id[j]]);MIN[i]=Min(MIN[i],v[id[j]]);
}
MAX2[i]=v[id[R[i]]],MIN2[i]=v[id[R[i]]];
for(RG int j=R[i]-1;j>=L[i];j--){
MAXV2[i]=Max(MAXV2[i],v[id[j]]-MIN2[i]);
MAX2[i]=Max(MAX2[i],v[id[j]]);MIN2[i]=Min(MIN2[i],v[id[j]]);
}
}
int Q=gi();
for(RG int i=1;i<=Q;i++){
int a=gi(),b=gi(),c=gi();
tot=0,tot2=0;lca(a,b);
minn=Inf,maxv=-Inf;
for(RG int j=1;j<=tot;j++) query2(q[j].r,q[j].l);
for(RG int j=tot2;j>=1;j--) query(q2[j].l,q2[j].r);
for(RG int j=1;j<=tot;j++) update(q[j].l,q[j].r,c);
for(RG int j=1;j<=tot2;j++) update(q2[j].l,q2[j].r,c);
if(maxv<0) puts("0");
else printf("%lld\n",maxv);
}
return 0;
}
bzoj 3999: [TJOI2015]旅游的更多相关文章
- bzoj 3999: [TJOI2015]旅游 LCT
没啥难的,inf 的值设小了调了半天~ code: #include <bits/stdc++.h> #define N 50003 #define lson t[x].ch[0] #de ...
- 【BZOJ3999】[TJOI2015]旅游(Link-Cut Tree)
[BZOJ3999][TJOI2015]旅游(Link-Cut Tree) 题面 BZOJ 洛谷 题解 一道不难的\(LCT\)题(用树链剖分不是为难自己吗,这种有方向的东西用\(LCT\)不是方便那 ...
- BZOJ 3999 旅游
.......好长啊. #include<iostream> #include<cstdio> #include<cstring> #include<algo ...
- BZOJ3999 [TJOI2015]旅游
题面:给定一个有$n$个节点的树,每个点又点权$v_i$,每次选取一条树链$[a, b]$,求出$max(v_i - v_j)$,其中$i, j \in [a, b]$且$i$出现在$j$前面,最后树 ...
- BZOJ 4000: [TJOI2015]棋盘( 状压dp + 矩阵快速幂 )
状压dp, 然后转移都是一样的, 矩阵乘法+快速幂就行啦. O(logN*2^(3m)) ------------------------------------------------------- ...
- BZOJ 1097: [POI2007]旅游景点atr( 最短路 + 状压dp )
先最短路预处理, 然后状压就行了 -------------------------------------------------------------------------- #include ...
- bzoj 3996: [TJOI2015]线性代数 [最小割]
3996: [TJOI2015]线性代数 题意:给出一个NN的矩阵B和一个1N的矩阵C.求出一个1*N的01矩阵A.使得 \(D=(A * B-C)* A^T\)最大.其中A^T为A的转置.输出D.每 ...
- BZOJ 3997: [TJOI2015]组合数学 [偏序关系 DP]
3997: [TJOI2015]组合数学 题意:\(n*m:\ n \le 1000\)网格图,每个格子有权值.每次从左上角出发,只能向下或右走.经过一个格子权值-1.至少从左上角出发几次所有权值为0 ...
- BZOJ 3998: [TJOI2015]弦论 [后缀自动机 DP]
3998: [TJOI2015]弦论 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2152 Solved: 716[Submit][Status] ...
随机推荐
- MySQL错误:2003-Can't connect to MySQL server on 'localhost'(10061 "unknown error")
今天数据库出了一点错误之后决定重装一下,结果卡在了一个问题上,连装了5遍,加上网上各种配置教程都没能结局,错误如下图所示: 最后忽然想到会不会是因为每一次卸载的时候没有彻底卸载干净,然后就彻彻底底卸载 ...
- 《Flask Web开发——基于Python的Web应用开发实践》一字一句上机实践(上)
目录 前言 第1章 安装 第2章 程序的基本结构 第3章 模板 第4章 Web表单 第5章 数据库 第6章 电子邮件 第7章 大型程序的结构 前言 学习Python也有一个半月时间了,学到现在感觉 ...
- Ceph luminous 安装配置
Ceph luminous 安装配置 #环境centos7 , Ceph V12 openstack pike 与 ceph 集成 http://www.cnblogs.com/elvi/p/7897 ...
- JAVA基础-JDBC二(常用的开源工具)
一.连接池 在实际的开发应用中,我们常常会对数据库进行大量的高并发的访问,而最原始的连接和操作方式并不能满足这种大量的访问,程序员为了追求更方便.更快捷.更科学安全的开发.第三方的工具类和Dao层的框 ...
- VMware中克隆虚拟机出现eth0改变为eth1情况
解决如下: 查看复制虚拟机网卡信息如下: root@jcfx-2 ~]# ifconfig eth1 Link encap:Ethernet HWaddr 00:0C:29:CC:32:63 inet ...
- FastDFS教程Ⅲ-文件服务器扩容
1.简介 FastDFS文件服务器在设计时,为了支持大容量,存储节点(服务器)采用了分卷(或分组)的组织方式.存储系统由一个或多个卷组成,卷与卷之间的文件是相互独立的,所有卷的文件容量累加就是 ...
- Java分布式锁实现详解
在进行大型网站技术架构设计以及业务实现的过程中,多少都会遇到需要使用分布式锁的情况.那么问题也就接踵而至,哪种分布式锁更适合我们的项目? 下面就这个问题,我做了一些分析: 分布式锁现状: 目前几乎很多 ...
- CountDownLatch的实现原理
CountDownLatch是java并发包中辅助并发的工具类,目的是让并发运行的代码在某一个执行点阻塞,直到所有条件都满足,这里的条件就是调用countDown()方法,有点类似计数器的功能. 用法 ...
- web前端素材整理汇总
最近一直搞前端开发,整理下前端用的一些常用素材,分享给大家 框架类 Vue:https://cn.vuejs.org/ iview:https://www.iviewui.com/ 插件类 Jquer ...
- hdoj 1285 确定比赛名次 【拓扑排序】
确定比赛名次 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...