【BZOJ3999】【TJOI2015】旅游 树剖
题目大意
给你一棵树,有\(n\)个点。有\(q\)个操作,每次要你从\(x\)到\(y\)的路径上选两个点,使得距离\(x\)比较远的点的点权\(-\)距离\(x\)比较近的点的点权最大,然后把这条路径上所有点的点权\(+v\)。
\(n,q\leq 50000\)
题解
这种题没什么意思,直接树剖就好了。
线段树上每个点记录最大值,最小值,从左往右走和从右往左走的最大收益。
时间复杂度:\(O(n+q\log^2 n)\)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
#include<functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
if(a>b)
swap(a,b);
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
int rd()
{
int s=0,c;
while((c=getchar())<'0'||c>'9');
do
{
s=s*10+c-'0';
}
while((c=getchar())>='0'&&c<='9');
return s;
}
int upmin(int &a,int b)
{
if(b<a)
{
a=b;
return 1;
}
return 0;
}
int upmax(int &a,int b)
{
if(b>a)
{
a=b;
return 1;
}
return 0;
}
struct pp
{
ll ma,mi;
ll s1,s2;
pp()
{
ma=mi=s1=s2=0;
}
};
pp merge(pp a,pp b)
{
pp c;
c.s1=max(b.ma-a.mi,max(a.s1,b.s1));
c.s2=max(a.ma-b.mi,max(a.s2,b.s2));
c.ma=max(a.ma,b.ma);
c.mi=min(a.mi,b.mi);
return c;
}
pp rev(pp a)
{
swap(a.s1,a.s2);
return a;
}
int c[100010];
namespace seg
{
struct tree
{
int ls,rs;
int l,r;
ll t;
pp s;
};
tree a[100010];
int cnt;
void build(int &p,int l,int r)
{
p=++cnt;
a[p].l=l;
a[p].r=r;
if(l==r)
{
a[p].s.ma=a[p].s.mi=c[l];
return;
}
int mid=(l+r)>>1;
build(a[p].ls,l,mid);
build(a[p].rs,mid+1,r);
a[p].s=merge(a[a[p].ls].s,a[a[p].rs].s);
}
void add(int p,ll v)
{
a[p].s.ma+=v;
a[p].s.mi+=v;
a[p].t+=v;
}
void push(int p)
{
if(a[p].t&&a[p].ls!=a[p].r)
{
add(a[p].ls,a[p].t);
add(a[p].rs,a[p].t);
a[p].t=0;
}
}
void add(int p,int l,int r,int v)
{
if(l<=a[p].l&&r>=a[p].r)
{
add(p,v);
return;
}
push(p);
int mid=(a[p].l+a[p].r)>>1;
if(l<=mid)
add(a[p].ls,l,r,v);
if(r>mid)
add(a[p].rs,l,r,v);
a[p].s=merge(a[a[p].ls].s,a[a[p].rs].s);
}
pp query(int p,int l,int r)
{
if(l<=a[p].l&&r>=a[p].r)
return a[p].s;
push(p);
int mid=(a[p].l+a[p].r)>>1;
if(r<=mid)
return query(a[p].ls,l,r);
if(l>mid)
return query(a[p].rs,l,r);
return merge(query(a[p].ls,l,r),query(a[p].rs,l,r));
}
}
struct graph
{
int v[100010];
int t[100010];
int h[50010];
int n;
graph()
{
n=0;
}
void add(int x,int y)
{
n++;
v[n]=y;
t[n]=h[x];
h[x]=n;
}
};
graph g;
struct p
{
int f,w,t,d,ms,s;
};
p a[100010];
int wcnt;
void dfs1(int x,int fa,int dep)
{
a[x].f=fa;
a[x].d=dep;
a[x].s=1;
int ms=0;
int i;
for(i=g.h[x];i;i=g.t[i])
if(g.v[i]!=fa)
{
dfs1(g.v[i],x,dep+1);
if(a[g.v[i]].s>ms)
{
ms=a[g.v[i]].s;
a[x].ms=g.v[i];
}
a[x].s+=a[g.v[i]].s;
}
}
void dfs2(int x,int top)
{
a[x].w=++wcnt;
a[x].t=top;
if(!a[x].ms)
return;
dfs2(a[x].ms,top);
int i;
for(i=g.h[x];i;i=g.t[i])
if(g.v[i]!=a[x].f&&g.v[i]!=a[x].ms)
dfs2(g.v[i],g.v[i]);
}
int prize[100010];
int rt;
ll query(int x,int y,int z)
{
pp s1,s2;
s1.ma=s1.mi=0x7fffffff;
s2.ma=s2.mi=-0x7fffffff;
while(a[x].t!=a[y].t)
if(a[a[x].t].d>a[a[y].t].d)
{
s1=merge(s1,rev(seg::query(rt,a[a[x].t].w,a[x].w)));
seg::add(rt,a[a[x].t].w,a[x].w,z);
x=a[a[x].t].f;
}
else
{
s2=merge(seg::query(rt,a[a[y].t].w,a[y].w),s2);
seg::add(rt,a[a[y].t].w,a[y].w,z);
y=a[a[y].t].f;
}
if(a[x].w<a[y].w)
{
s2=merge(seg::query(rt,a[x].w,a[y].w),s2);
seg::add(rt,a[x].w,a[y].w,z);
}
else
{
s1=merge(s1,rev(seg::query(rt,a[y].w,a[x].w)));
seg::add(rt,a[y].w,a[x].w,z);
}
s1=merge(s1,s2);
return s1.s1;
}
int main()
{
open("bzoj3999");
int n,q;
scanf("%d",&n);
int i,x,y,z;
for(i=1;i<=n;i++)
scanf("%d",&prize[i]);
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
g.add(x,y);
g.add(y,x);
}
dfs1(1,0,1);
dfs2(1,1);
for(i=1;i<=n;i++)
c[a[i].w]=prize[i];
seg::build(rt,1,n);
scanf("%d",&q);
for(i=1;i<=q;i++)
{
scanf("%d%d%d",&x,&y,&z);
ll ans=query(x,y,z);
printf("%lld\n",ans);
}
return 0;
}
【BZOJ3999】【TJOI2015】旅游 树剖的更多相关文章
- BZOJ3999:[TJOI2015]旅游(树链剖分)
Description 为了提高智商,ZJY准备去往一个新世界去旅游.这个世界的城市布局像一棵树.每两座城市之间只有一条路径可 以互达.每座城市都有一种宝石,有一定的价格.ZJY为了赚取最高利益,她会 ...
- BZOJ3999 [TJOI2015]旅游 【树剖 + 线段树】
题目 为了提高智商,ZJY准备去往一个新世界去旅游.这个世界的城市布局像一棵树.每两座城市之间只有一条路径可 以互达.每座城市都有一种宝石,有一定的价格.ZJY为了赚取最高利益,她会选择从A城市买入再 ...
- P1505 [国家集训队]旅游[树剖]
题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路 ...
- 2019.01.20 bzoj3999: [TJOI2015]旅游(树链剖分)
传送门 树链剖分菜题. 题意不清差评. 题意简述(保证清晰):给一棵带权的树,每次从aaa走到bbb,在走过的路径上任意找两个点,求后访问的点与先访问的点点权差的最大值. 思路: 考虑暴力:维护路径的 ...
- BZOJ3999 [TJOI2015]旅游
题面:给定一个有$n$个节点的树,每个点又点权$v_i$,每次选取一条树链$[a, b]$,求出$max(v_i - v_j)$,其中$i, j \in [a, b]$且$i$出现在$j$前面,最后树 ...
- 【BZOJ3999】[TJOI2015]旅游(Link-Cut Tree)
[BZOJ3999][TJOI2015]旅游(Link-Cut Tree) 题面 BZOJ 洛谷 题解 一道不难的\(LCT\)题(用树链剖分不是为难自己吗,这种有方向的东西用\(LCT\)不是方便那 ...
- BZOJ_2157_旅游_树剖+线段树
BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...
- BZOJ2157 旅游 【树剖 或 LCT】
题目 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径. ...
- luoguP1505旅游(处理边权的树剖)
/* luogu1505 非常简单的处理边权的树剖题. 在树上将一条边定向,把这条边的权值赋给这条边的出点 树剖的时候不计算lca权值即可 */ #include<bits/stdc++.h&g ...
随机推荐
- H5 字体属性补充
04-字体属性补充 abc我是段落 <!DOCTYPE html> <html lang="en"> <head> <meta chars ...
- elasticsearch elk最全java api 搜索 聚合、嵌套查询
目录 一. 一般查询... 2 (一) matchAllQuery(client). 2 (二) matchQuery(client);3 (三) multiMatchQuery(client);3 ...
- git repository description
Git - Plumbing and Porcelainhttps://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain gith ...
- Oracle SQL优化原则
原文:http://bbs.landingbj.com/t-0-240353-1.html 1.选用适合的 ORACLE 优化器 2.访问 Table 的方式 3.共享SQL语句 共享的语句必须满足三 ...
- array_filter、array_walk、array_map的区别
<?php $arr=array( 1,2,3,4,5,6 ); function filter($var){ if($var%2==0) return true; } $data=array_ ...
- Tomcat Windows 系统下安装及注意事项
1 获取Tomcat 安装包 http://tomcat.apache.org/ tar.gz 文件是Linux系统下的安装版本 exe文件是 Windows系统下的安装版本 zip 文件是Wind ...
- socket通信原理三次握手和四次握手详解
对TCP/IP.UDP.Socket编程这些词你不会很陌生吧?随着网络技术的发展,这些词充斥着我们的耳朵.那么我想问: 1. 什么是TCP/IP.UDP?2. Sock ...
- K8S入门学习
一.k8s是个什么鬼? k8s全名:kubernetes 它是一个工具,在linux上管理应用生命周期的一个工具. 二.k8s有什么卵用? 1.当你把项目部署到服务器集群上,一台服务器挂了,k8s它可 ...
- Oracle minus用法详解及应用实例
本文转载:https://blog.csdn.net/jhon_03/article/details/78321937 Oracle minus用法 “minus”直接翻译为中文是“减”的意思,在Or ...
- ES 6 系列 - 变量声明
let 和 const let 声明 (一)基本用法 let 声明的变量只在块级作用域内有效,出了该块则报错,最常见且适合的地方在 for 循环中: var a = []; for (var i = ...