[CSP-S模拟测试]:椎(线段树维护区间最值和单调栈)
题目描述
虽不能至,心向往之。
$Treap=Tree+Heap$
椎$=$树$+$堆
小$\pi$学习了计算机科学中的数据结构$Treap$。
小$\pi$知道$Treap$指的是一种树。
小$\pi$还知道$Treap$节点上有两个权值$k$和$w$,其中$k$满足二叉搜索树性质。$w$满足堆性质。
小$\pi$还知道在$k$和$w$都各不相同的时候,$Treap$的形态是固定的。
但是小$\pi$不知道这道题目的做法。
这道题目要求你维护一个大根堆$Treap$,要求支持$n$个操作:
$0\ k\ w$:插入一个关键字为$k$,权值为$w$的点。
$1\ k$:删除一个关键字为$k$的点。
$2\ ku\ kv$:返回关键字分别为$k_u$和$k_v$两个节点的距离
保证任意时刻树中结点$key$和$weight$都是两两不同的。不会删除当前$Treap$中不存在的点
小$\pi$找到了学信息学竞赛的你
输入格式
输入的第一行包含一个正整数$n$,表示操作数。
下面$n$行,为上述操作之一。
输出格式
对于每个$2$操作,返回对应答案。
样例
样例输入:
12
0 4 17
0 10 38
0 2 21
0 1 61
2 1 10
2 10 4
1 10
1 1
0 8 42
2 8 4
2 8 2
2 4 2
样例输出:
1
2
2
1
1
数据范围与提示
对于$20\%$的数据,$n\leqslant 100$。
对于$40\%$的数据,$n\leqslant 1,000$。
对于$60\%$的数据,$n\leqslant 10,000$。
对于$100\%$的数据,$n\leqslant 200,000,0\leqslant k,w,k_u,k_v\leqslant 2^{31}$。
题解
一句话题意:求$Treap$上两点的距离。
$Treap$毕竟还是一棵树,考虑对一棵树如何求两个点$(u,v)$之间的距离,无非就是$depth[u]+depth[v]-2\times depth[lca]$。
那么对于这道题,就是要想办法求出$lca$和$depth$就好了。
因为$key$满足二叉搜索树性质,也就是中序遍历从小到大;那么不妨将其拍扁放在序列上,也就是说维护一个$key$从小到大的序列。
注意空间问题,因为这道题$key$值只与相对大小有关,而与具体值无关,所以可以离散化,并在序列中提前留好坑即可。
那么来考虑$lca$是什么。
画个图便可以知道,$k_u$和$k_v$的$lca$就是在这个序列上$k_u$和$k_v$之间的$weight$值的最大值,用线段树维护即可。
接着考虑$depth$。
对于点$u$,其在序列上左(右)边第一个$weight$比它大的一定是它的祖先;而一个点的$depth=$其祖先的个数,对于这道题也就是$u$左边和右边的上升序列长度之和(注意这里的上升序列是指碰见比它大的就选上,而不是求最长上升子序列)。
考虑平常维护上升序列可以用单调栈,这道题可以用线段树维护单调栈(然而考场并不会,花了一个小时$zzyy$了一下)。
知道了$lca$和$depth$,这道题也就解决了。
时间复杂度:$\Theta(n\log^2 n)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct rec{int opt,k,w;}e[300000];
unordered_map<int,int>mp;
int n;
int a[300000];
int trmx[1000000],trl[1000000],trr[1000000],trns[1000000],pos[1000000],cnt;
int pushupl(int x,int l,int r,int w)
{
if(l==r)return trmx[x]>w;int mid=(l+r)>>1;
if(trmx[L(x)]<=w)return pushupl(R(x),mid+1,r,w);
return trl[x]-trl[L(x)]+pushupl(L(x),l,mid,w);
}
int pushupr(int x,int l,int r,int w)
{
if(l==r)return trmx[x]>w;int mid=(l+r)>>1;
if(trmx[R(x)]<=w)return pushupr(L(x),l,mid,w);
return trr[x]-trr[R(x)]+pushupr(R(x),mid+1,r,w);
}
void pushup(int x,int l,int r)
{
if(trmx[L(x)]<=trmx[R(x)]){trns[x]=trns[R(x)];trmx[x]=trmx[R(x)];}
else{trns[x]=trns[L(x)];trmx[x]=trmx[L(x)];}int mid=(l+r)>>1;
trl[x]=trl[L(x)]+pushupl(R(x),mid+1,r,trmx[L(x)]);
trr[x]=trr[R(x)]+pushupr(L(x),l,mid,trmx[R(x)]);
}
void add(int x,int l,int r,int k,int w)
{
if(l==r){trns[x]=k;trmx[x]=w;trl[x]=trr[x]=1;return;}
int mid=(l+r)>>1;
if(k<=mid)add(L(x),l,mid,k,w);
else add(R(x),mid+1,r,k,w);
pushup(x,l,r);
}
void del(int x,int l,int r,int k)
{
if(l==r){trns[x]=k;trmx[x]=-0x3f3f3f3f;trl[x]=trr[x]=0;return;}
int mid=(l+r)>>1;
if(k<=mid)del(L(x),l,mid,k);
else del(R(x),mid+1,r,k);
pushup(x,l,r);
}
pair<int,int> lca(int x,int l,int r,int res1,int res2)
{
if(res1<=l&&r<=res2)return make_pair(trmx[x],trns[x]);
int mid=(l+r)>>1;
if(res2<=mid)return lca(L(x),l,mid,res1,res2);
if(mid<res1)return lca(R(x),mid+1,r,res1,res2);
pair<int,int> flag1=lca(L(x),l,mid,res1,res2);
pair<int,int> flag2=lca(R(x),mid+1,r,res1,res2);
if(flag1<flag2)return flag2;return flag1;
}
pair<int,int> askl(int x,int l,int r,int k,int w)
{
if(!k)return make_pair(0,0);
if(r<=k)return make_pair(max(w,trmx[x]),pushupr(x,l,r,w));
int mid=(l+r)>>1;
if(k<=mid)return askl(L(x),l,mid,k,w);
pair<int,int> flag=askl(R(x),mid+1,r,k,w);
pair<int,int> res=askl(L(x),l,mid,k,max(w,flag.first));
res.second+=flag.second;
return res;
}
pair<int,int> askr(int x,int l,int r,int k,int w)
{
if(l>cnt)return make_pair(0,0);
if(k<=l)return make_pair(max(w,trmx[x]),pushupl(x,l,r,w));
int mid=(l+r)>>1;
if(mid<k)return askr(R(x),mid+1,r,k,w);
pair<int,int> flag=askr(L(x),l,mid,k,w);
pair<int,int> res=askr(R(x),mid+1,r,k,max(w,flag.first));
res.second+=flag.second;
return res;
}
int getdep(int x){return askl(1,1,cnt,x-1,pos[x]).second+askr(1,1,cnt,x+1,pos[x]).second;}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&e[i].opt);
switch(e[i].opt)
{
case 0:scanf("%d%d",&e[i].k,&e[i].w);a[++a[0]]=e[i].k;break;
case 1:scanf("%d",&e[i].k);break;
case 2:scanf("%d%d",&e[i].k,&e[i].w);if(e[i].k>e[i].w)swap(e[i].k,e[i].w);break;
}
}
sort(a+1,a+a[0]+1);
for(int i=1;i<=a[0];i++){if(a[i]!=a[i-1])cnt++;mp[a[i]]=cnt;}
memset(trmx,-0x3f,sizeof(trmx));
for(int i=1;i<=n;i++)
switch(e[i].opt)
{
case 0:add(1,1,cnt,mp[e[i].k],e[i].w);pos[mp[e[i].k]]=e[i].w;break;
case 1:del(1,1,cnt,mp[e[i].k]);pos[mp[e[i].k]]=-0x3f3f3f3f;break;
case 2:printf("%d\n",getdep(mp[e[i].k])+getdep(mp[e[i].w])-2*getdep(lca(1,1,cnt,mp[e[i].k],mp[e[i].w]).second));break;
}
return 0;
}
rp++
[CSP-S模拟测试]:椎(线段树维护区间最值和单调栈)的更多相关文章
- 滑动窗口(poj,线段树维护区间最值)
题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...
- 【8.26校内测试】【重构树求直径】【BFS模拟】【线段树维护DP】
题目性质比较显然,相同颜色联通块可以合并成一个点,重新建树后,发现相邻两个点的颜色一定是不一样的. 然后发现,对于一条链来说,每次把一个点反色,实际上使点数少了2个.如下图 而如果一条链上面有分支,也 ...
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...
- 【uoj#164】[清华集训2015]V 线段树维护历史最值
题目描述 给你一个长度为 $n$ 的序列,支持五种操作: $1\ l\ r\ x$ :将 $[l,r]$ 内的数加上 $x$ :$2\ l\ r\ x$ :将 $[l,r]$ 内的数减去 $x$ ,并 ...
- 【bzoj3064】Tyvj 1518 CPU监控 线段树维护历史最值
题目描述 给你一个序列,支持4种操作:1.查询区间最大值:2.查询区间历史最大值:3.区间加:4.区间赋值. 输入 第一行一个正整数T,表示Bob需要监视CPU的总时间. 然后第二行给出T个数表示在你 ...
- CF213E Two Permutations 线段树维护哈希值
当初竟然看成子串了$qwq$,不过老师的$ppt$也错了$qwq$ 由于子序列一定是的排列,所以考虑插入$1$到$m$到$n-m+1$到$n$; 如何判断呢?可以用哈希$qwq$: 我们用线段树维护哈 ...
- Can you answer these queries V SPOJ - GSS5 (分类讨论+线段树维护区间最大子段和)
recursion有一个整数序列a[n].现在recursion有m次询问,每次她想知道Max { A[i]+A[i+1]+...+A[j] ; x1 <= i <= y1 , x2 &l ...
- 线段树维护区间前k小
线段树维护区间前k小 $ solution: $ 觉得超级钢琴太麻烦?在这里线段树提供一条龙服务 . 咳咳,开始讲正题!这道题我们有一个和超级钢琴复杂度一样 $ ~O(~\sum x\times lo ...
- CodeForces - 587E[线段树+线性基+差分] ->(线段树维护区间合并线性基)
题意:给你一个数组,有两种操作,一种区间xor一个值,一个是查询区间xor的结果的种类数 做法一:对于一个给定的区间,我们可以通过求解线性基的方式求出结果的种类数,而现在只不过将其放在线树上维护区间线 ...
随机推荐
- Ubuntu下软件打开时状态图标与原始图标不重合问题解决
问题描述 如下图书所示,pycharm打开时,运行的pycharm图标与原始的在收藏夹中的图标不重合.而其他软件不会这样,运行软件的图标与原始图标会重合, 解决办法 把鼠标悬浮在打开的pycharm上 ...
- aop设计原理(转)
本文摘自 博文--<Spring设计思想>AOP设计基本原理 0.前言 Spring 提供了AOP(Aspect Oriented Programming) 的支持, 那么,什么是AOP呢 ...
- 09、RNA降解图的计算过程
RNA降解是影响芯片质量的一个很重要的因素,因为RNA是从5’开始降解的,所以理论5’的荧光强度要低于3’.RNA降解曲线可以表现这种趋势. 以样品GSM286756.CEL和GSM286757.CE ...
- RabbitMQ入门教程(十):队列声明queueDeclare
原文:RabbitMQ入门教程(十):队列声明queueDeclare 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https:// ...
- Vim插件YouCompleteMe安装记录(号称最难装的Vim插件?)
使用 PulginInstall 安装就不要想了,如果你没有梯子的话 自己的 ssr 被封,使用的同事的 ss,但是同事设置的加密方式在 linux 上的 ss 应用不支持... 好吧,直接上过程 1 ...
- h5与app混合开发,jsbridge
https://juejin.im/post/5bda6f276fb9a0226d18931f https://juejin.im/post/5abca877f265da238155b6bc http ...
- Win7安装Visual Studio 2019闪退问题
最近在Win7 系统上安装最新版的VS2019发现 每次在这个画面之后就闪退了,即便换了台电脑也是一样的情况,于是我意识到,这应该是系统本身的问题 经过调查发现是只需要安装两个更新就可以了 这两个更新 ...
- python-字符编码的转换
python-字符编码的转换 1.了解基础知识 ASCII 一个英文,占一个字节.只能存英文和特殊字符. gb2312 约可以存7000中文 gb1830 约可以存27000中文 gbk 默认中文, ...
- centos7部署nagios(二)
一.Nagios简介 分类: 监控 undefined Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows.Linux和Unix的主机状态,交换机路由器等网络设置,打印机等.在系 ...
- HTTP/1.1-HTTP/2.0-HTTP/3.0-HTTPS
HTTP/1.1 网上关于HTTP/1.1的讨论多是基于RFC2616文档,而IETF已更新了HTTP/1.1并将其分为六个部分,使协议变得更简单易懂,对老版本RFC2616中模糊不清的部分做了解释 ...