答案即区间$[l,r]$的笛卡尔树上,左右子树有一个为空的点到根路径和(定义此为的该点答案)的max,

对求区间笛卡尔树复杂度为$o(n)$,无法通过,因此在全局笛卡尔树中考虑此问题

设$k$为$l$和$r$的lca,那么$i$的答案就是$i$到$k$路径中在$[l,r]$中的部分的和

对于$i$所在子树分类,即将$[l,r]$分为$[l,k)$和$(k,r]$两部分(分别求max),以下以左半部分为例:

考虑$i$到$k$的链,由于$i$在$k$左子树中,因此这条链也时刻在$k$左子树中,即其一定在$k$也就是$r$的左边,因此只需要考虑这个位置大于等于$l$

进一步的,再求$l$和$i$的lca(记为$j$),由于是lca且$l\le i$,因此$l$一定在$j$的左子树中,$i$在$j$的右子树中,因此$i$到$j$的这一部分一定都在$l$的右边,换言之可以枚举lca,直接对右子树内所有点深度取max

还要考虑$j$到$k$的部分,即求这一部分中在$l$右边的数之和,这件事是与$l$无关而仅和$j$本身有关,凡是这条链上其儿子是其右儿子的都不能被计算

(因为这就说明了$k$在其右子树,$l$又在$k$子树内,即$l$在其的右边,反之就说明$l$在左边)

根据上面的性质,具体过程如下——

预处理出以下三个数组:$s_{1}[k]$表示$k$到根路径中所有点的和,$s_{2}[k]$表示其中所有儿子是左儿子的点之和(特别的,$k$都计算入内),$mx[k]$表示$k$子树中满足左右子树有一个为空的点的$s_{1}[k]$的最大值

考虑询问$[l,k)$,暴力枚举$j$,则对于给定的$j$,其对答案的贡献为$mx[rs[j]]-s_{1}[j]+s_{2}[j]-s_{2}[k]+w[k]$(注意$j$一定在$l$的右边,否则不可能是$l$和$i$的lca),贡献是取max

离线,将询问挂在$l$上,然后遍历笛卡尔树,对于点$k$,将$mx[rs[k]]-s_{1}[k]+s_{2}[k]$记在以$k$的深度为下标的线段树上,然后搜索左子树,当搜索右子树时撤销此记录

对于询问,求出$k$(指询问的顶点)的深度+1到$l$的深度这段区间在线段树上的最大值即可(由于$l$的右子树也是可以的,因此先修改再询问)

(右半部分类似,即只考虑其儿子是右儿子的点)

注意要开long long,时间复杂度为$o(n\log_{2}n)$,可以通过

 1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 500005
4 #define ll long long
5 #define L (k<<1)
6 #define R (L+1)
7 #define mid (l+r>>1)
8 vector<pair<int,int> >vl[N],vr[N];
9 int n,q,x,y,a[N],w[N],st[N],ls[N],rs[N],s[N],f[N][21];
10 ll s1[N],s2[N],s3[N],mx[N],ans[N],tr[N<<2];
11 int lca(int x,int y){
12 if (s[x]<s[y])swap(x,y);
13 for(int i=20;i>=0;i--)
14 if (s[f[x][i]]>=s[y])x=f[x][i];
15 if (x==y)return x;
16 for(int i=20;i>=0;i--)
17 if (f[x][i]!=f[y][i]){
18 x=f[x][i];
19 y=f[y][i];
20 }
21 return f[x][0];
22 }
23 void dfs(int k,int fa){
24 if (!k)return;
25 s[k]=s[fa]+1;
26 s1[k]=s1[fa]+w[k];
27 s2[k]+=s2[fa]+w[k];
28 s3[k]+=s3[fa]+w[k];
29 f[k][0]=fa;
30 for(int i=1;i<=20;i++)f[k][i]=f[f[k][i-1]][i-1];
31 if (ls[k])s3[ls[k]]=-w[k];
32 dfs(ls[k],k);
33 if (rs[k])s2[rs[k]]=-w[k];
34 dfs(rs[k],k);
35 mx[k]=max(mx[ls[k]],mx[rs[k]]);
36 if ((!ls[k])||(!rs[k]))mx[k]=max(mx[k],s1[k]);
37 }
38 void update(int k,int l,int r,int x,ll y){
39 if (l==r){
40 tr[k]=y;
41 return;
42 }
43 if (x<=mid)update(L,l,mid,x,y);
44 else update(R,mid+1,r,x,y);
45 tr[k]=max(tr[L],tr[R]);
46 }
47 ll query(int k,int l,int r,int x,int y){
48 if ((l>y)||(x>r))return -1e15;
49 if ((x<=l)&&(r<=y))return tr[k];
50 return max(query(L,l,mid,x,y),query(R,mid+1,r,x,y));
51 }
52 void calc_l(int k){
53 if (!k)return;
54 if (!rs[k])update(1,1,n,s[k],s2[k]);
55 else update(1,1,n,s[k],mx[rs[k]]-s1[k]+s2[k]);
56 for(int i=0;i<vl[k].size();i++){
57 x=vl[k][i].first,y=vl[k][i].second;
58 ans[y]=max(ans[y],query(1,1,n,s[x]+1,s[k])-s2[x]+w[x]);
59 }
60 calc_l(ls[k]);
61 update(1,1,n,s[k],-1e15);
62 calc_l(rs[k]);
63 }
64 void calc_r(int k){
65 if (!k)return;
66 if (!ls[k])update(1,1,n,s[k],s3[k]);
67 else update(1,1,n,s[k],mx[ls[k]]-s1[k]+s3[k]);
68 for(int i=0;i<vr[k].size();i++){
69 x=vr[k][i].first,y=vr[k][i].second;
70 ans[y]=max(ans[y],query(1,1,n,s[x]+1,s[k])-s3[x]+w[x]);
71 }
72 calc_r(rs[k]);
73 update(1,1,n,s[k],-1e15);
74 calc_r(ls[k]);
75 }
76 int main(){
77 scanf("%d%d",&n,&q);
78 for(int i=1;i<=n;i++)scanf("%d",&a[i]);
79 for(int i=1;i<=n;i++)scanf("%d",&w[i]);
80 for(int i=1;i<=n;i++){
81 while ((st[0])&&(a[st[st[0]]]<a[i]))ls[i]=st[st[0]--];
82 if (st[0])rs[st[st[0]]]=i;
83 st[++st[0]]=i;
84 }
85 mx[0]=-1e15;
86 dfs(st[1],0);
87 for(int i=1;i<=q;i++){
88 scanf("%d%d",&x,&y);
89 int z=lca(x,y);
90 ans[i]=max(s2[x]-s2[z],s3[y]-s3[z])+w[z];
91 if (x<z)vl[x].push_back(make_pair(z,i));
92 if (z<y)vr[y].push_back(make_pair(z,i));
93 }
94 for(int i=1;i<=n;i++)update(1,1,n,i,-1e15);
95 calc_l(st[1]);
96 calc_r(st[1]);
97 for(int i=1;i<=q;i++)printf("%lld\n",ans[i]);
98 }

[luogu5654]基础函数练习题的更多相关文章

  1. 6、50道JAVA基础编程练习题跟答案

    50道JAVA基础编程练习题 [程序1] 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 程序分析 ...

  2. 50道JAVA基础编程练习题

    50道JAVA基础编程练习题 [程序1] 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子对数为多少? 程序分析 ...

  3. 50道JAVA基础编程练习题 - 题目

    50道JAVA基础编程练习题[1]题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? [2]题目:判断 ...

  4. 【UOJ#228】基础数据结构练习题 线段树

    #228. 基础数据结构练习题 题目链接:http://uoj.ac/problem/228 Solution 这题由于有区间+操作,所以和花神还是不一样的. 花神那道题,我们可以考虑每个数最多开根几 ...

  5. 速战速决 (3) - PHP: 函数基础, 函数参数, 函数返回值, 可变函数, 匿名函数, 闭包函数, 回调函数

    [源码下载] 速战速决 (3) - PHP: 函数基础, 函数参数, 函数返回值, 可变函数, 匿名函数, 闭包函数, 回调函数 作者:webabcd 介绍速战速决 之 PHP 函数基础 函数参数 函 ...

  6. python基础——函数的参数

    python基础——函数的参数 定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了.对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复 ...

  7. python基础—函数嵌套与闭包

    python基础-函数嵌套与闭包 1.名称空间与作用域 1 名称空间分为: 1 内置名称空间   内置在解释器中的名称 2 全局名称空间   顶头写的名称 3 局部名称空间 2 找一个名称的查找顺序: ...

  8. python基础—函数装饰器

    python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...

  9. uoj #228. 基础数据结构练习题 线段树

    #228. 基础数据结构练习题 统计 描述 提交 自定义测试 sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧. 在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手.于是她的 ...

随机推荐

  1. WebXml文件与SpringMVC的联系

    WebXml文件与SpringMVC的联系 无论采用何种框架来进行Java Web的开发,只要是Web项目必须在WEB-INF下有web.xml,这是java规范. 当然,我们最早接触到Java We ...

  2. Jave Hbase AP

    Hbase API 类和数据模型的对应关系 HBaseAdmin 类:org.apache.hadoop.hbase.client.HBaseAdmin 作用:提供了一个接口来管理 HBase 数据库 ...

  3. 从零入门 Serverless | 架构的演进

    作者 | 许晓斌 阿里云高级技术专家 本文整理自<Serverless 技术公开课>,关注"Serverless"公众号,回复 入门 ,即可获取 Serverless ...

  4. 题解 [NOI2019]弹跳

    题目传送门 题目大意 给出 \(n\) 做城市,每座城市都有横纵坐标 \(x,y\).现在给出 \(m\) 个限制 \(p,t,l,r,d,u\),表示从 \(p\) 城市出发,可以花费 \(t\) ...

  5. 初识Linux shell

    目录 初识Linux shell Linux 深入探究Linux内核 系统内存管理 交换空间 页面 换出 软件程序管理 Linux中的进程 Linux系统的运行级 硬件设备管理 插入设备驱动代码的方法 ...

  6. Dapr-简介及环境搭建

    一.Dapr是什么? Dapr 是一个可移植的.事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的.无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架. 在 ...

  7. Python技法3:匿名函数、回调函数和高阶函数

    1.定义匿名或内联函数 如果我们想提供一个短小的回调函数供sort()这样的函数用,但不想用def这样的语句编写一个单行的函数,我们可以借助lambda表达式来编写"内联"式的函数 ...

  8. 对epoll机制的学习理解v1

    epoll机制 wrk用非阻塞多路复用IO技术创造出大量的连接,从而达到很好的压力测试效果.epoll就是实现IO多路复用的关键. 本节是对epoll的本质的学习总结,进一步的参考资料为: <深 ...

  9. cookie和session和localStorage的区别

    这三个都是保存在浏览器端,而且都是同源的. Session仅在当前浏览器窗口关闭有效,不能持久保存 Localstorage始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据 Cookie只在设置 ...

  10. Vue2源码解读 - 响应式原理及简单实现

    直接进入主题了,想必大家都知道实现vue响应式核心方法就是 Object.defineProperty,那就从它开始说 Object.defineProperty 缺点: 深度监听,需要递归到底,一次 ...