[JZOJ5977] 【清华2019冬令营模拟12.15】堆
题目
其中n,q≤500000n,q\leq 500000n,q≤500000
题目大意
让你维护一个堆。支持一下操作:
在某个点的下面加上另一个点,然后进行上浮操作。
询问某一点的权值。
思考历程
一眼看这题,诶,不就是那道中学生数据结构题吗?
直接树链剖分,然后splay一波搞定!
思想还是很简单的!
但是感觉有点长……
正解
上面的这个解法算是一个正解吧。
但是我还是没打,因为代码可能很长……(想一想,又树链剖分,又splay的有点麻烦)
然后这题LCT也可以做!就是LCT和一个splay!由于LCT本来就是用splay来实现的,所以,在打板的时候还比较容易,只不过……
先不要说。现在说一说解法。
我们知道,上浮操作其实就是轮换操作。但是,如果我们直接在LCT中轮换,那么我们会将点的位置改变,不只是权值的改变!
所以说,我们要再用一个splay来维护一下链上点的权值。对于LCT上的每一条链(也就是LCT中的每一个splay),另外维护一个以权值为关键字的splay。这两个splay其中的顺序是一一对应的。当我们要轮换的时候,只需要轮换那个splay中的值。在查询的时候查与其对应位置的值就好了。
不过再想想,代码还是有点复杂的,虽然比较简单。我们再进行LCT操作的时候,我们还要维护一下那些splay,所以要加一些东西!当然,在宏观的意义上,这个还是比较好理解的。
然后还有一个比较简单的做法:离线,树链剖分和权值线段树!
这个似乎比较好打很多……在这里理清一下思路。
我们先将整棵树建出来(当然,是树的最后形态),然后树链剖分剖成许多条重链!
对于每一条重链,我们分别维护一个权值线段树。
在我们进行操作的时候,如果是询问,那就直接通过它在重链中的位置,在权值线段树中把它给找出来。
如果是插入一个点,那就将其加入权值线段树中(之前是无限大),然后和重链顶端的父亲上面的值对比一下,如果比它小,那就进行替换,然后继续往上跳。
其实不一定要使用权值线段树,平衡树也是一个不错的选择……
总感觉这题的正解有好多……
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1000000
#define Q 500000
#define MAX 1000001
int n,nn,q;
struct EDGE{
int to;
EDGE *las;
} e[N+1];
int ne;
EDGE *last[N+1];
inline void link(int u,int v){
e[++ne]={v,last[u]};
last[u]=e+ne;
}
int a[N+1];
struct Oper{
bool op;
int x;
} o[Q+1];
int fa[N+1],siz[N+1],dep[N+1],hs[N+1];
void init1(int);
int top[N+1];
void init2(int,int);
struct Segment_Tree{
int l,r;
int sum;
} seg[20000001];
int cnt;
void add(int,int,int,int,int);
int kth(int,int,int,int);
int tos[N+1];//tos[i]表示i所在的重链对应的线段树根节点的编号
inline void insert(int);
int main(){
freopen("heap.in","r",stdin);
freopen("heap.out","w",stdout);
scanf("%d%d",&n,&q);
for (int i=1;i<=n;++i){
scanf("%d%d",&fa[i],&a[i]);
if (fa[i])
link(fa[i],i);
}
nn=n;
for (int i=1;i<=q;++i){
int op;
scanf("%d",&op);
if (op==1){
++nn;
scanf("%d%d",&fa[nn],&a[nn]);
link(fa[nn],nn);
o[i]={0,nn};
}
else{
int x;
scanf("%d",&x);
o[i]={1,x};
}
}
init1(1);
init2(1,1);
for (int i=1;i<=nn;++i)
if (top[i]==i){
tos[i]=++cnt;
seg[cnt]={0,0,0};
}
for (int i=1;i<=nn;++i)
tos[i]=tos[top[i]];
for (int i=1;i<=n;++i)
add(tos[i],1,MAX,a[i],1);
for (int i=1;i<=q;++i)
if (o[i].op==0)
insert(o[i].x);
else
printf("%d\n",kth(tos[o[i].x],1,MAX,dep[o[i].x]-dep[top[o[i].x]]+1));
return 0;
}
void init1(int x){
dep[x]=dep[fa[x]]+1;
siz[x]=1;
for (EDGE *ei=last[x];ei;ei=ei->las){
init1(ei->to);
siz[x]+=siz[ei->to];
if (siz[ei->to]>siz[hs[x]])
hs[x]=ei->to;
}
}
void init2(int x,int t){
top[x]=t;
if (hs[x])
init2(hs[x],t);
for (EDGE *ei=last[x];ei;ei=ei->las)
if (ei->to!=hs[x])
init2(ei->to,ei->to);
}
void add(int k,int l,int r,int x,int c){
seg[k].sum+=c;
if (l==r)
return;
int mid=l+r>>1;
if (x<=mid){
if (!seg[k].l)
seg[k].l=++cnt;
add(seg[k].l,l,mid,x,c);
}
else{
if (!seg[k].r)
seg[k].r=++cnt;
add(seg[k].r,mid+1,r,x,c);
}
}
int kth(int k,int l,int r,int x){
if (l==r)
return l;
int mid=l+r>>1;
if (x<=seg[seg[k].l].sum)
return kth(seg[k].l,l,mid,x);
return kth(seg[k].r,mid+1,r,x-seg[seg[k].l].sum);
}
inline void insert(int x){
add(tos[x],1,MAX,a[x],1);
int v=a[x];
while (fa[top[x]]){
int y=fa[top[x]],mn=kth(tos[y],1,MAX,dep[y]-dep[top[y]]+1);//找出重链的父亲的值
if (v<mn){
//交换
add(tos[x],1,MAX,v,-1);
add(tos[x],1,MAX,mn,1);
add(tos[y],1,MAX,mn,-1);
add(tos[y],1,MAX,v,1);
x=y;
}
else
break;
}
}
总结
树链剖分真是一个好东西……
LCT真是一个好东西……
……
[JZOJ5977] 【清华2019冬令营模拟12.15】堆的更多相关文章
- JZOJ[5971]【北大2019冬令营模拟12.1】 party(1s,256MB)
题目 题目大意 给你一棵树,在树上的某一些节点上面有人,要用最小的步数和,使得这些人靠在一起.所谓靠在一起,即是任意两个人之间的路径上没有空的节点(也就是连在一起). N≤200N \leq 200N ...
- jzoj5990. 【北大2019冬令营模拟2019.1.6】Bear (状压dp)
题面 题解 我永远讨厌dp.jpg 搞了一个下午优化复杂度最后发现只要有一个小trick就可以A了→_→.全场都插头dp就我一个状压跑得贼慢-- 不难发现我们可以状压,对于每一行,用状态\(S\)表示 ...
- jzoj5991. 【北大2019冬令营模拟2019.1.6】Juice
题面 题解 好迷-- //minamoto #include<bits/stdc++.h> #define R register #define ll long long #define ...
- jzoj5989. 【北大2019冬令营模拟2019.1.6】Forest (set)
题面 题解 为了一点小细节卡了一个下午--我都怕我瞎用set把电脑搞炸-- 观察一次\(1\)操作会造成什么影响,比如说把\(A[i]\)从\(x\)改成\(y\): \(D[x]\)会\(-1\), ...
- jzoj5984. 【北大2019冬令营模拟2019.1.1】仙人掌 (分块)
题面 题解 数据结构做傻了.jpg 考虑每一个节点,它的儿子的取值最多只有\(O(\sqrt {m})\)种,那么可以用一个双向链表维护儿子的所有取值以及该取值的个数,那么对儿子节点修改一个值就是\( ...
- jzoj5983. 【北大2019冬令营模拟2019.1.1】多边形 (组合数学)
这其实是道打表题--你看我代码就知道了-- 咳咳来点严谨证明好了-- 前方高能请注意 首先,正多边形近似于圆,可以看做在圆里内接多边形.圆内接多边形最多只有三个锐角.因为凸多边形的外角和为\(360\ ...
- noip模拟12[简单的区间·简单的玄学·简单的填数]
noip模拟12 solutions 这次考试靠的还是比较好的,但是还是有不好的地方, 为啥嘞??因为我觉得我排列组合好像白学了诶,文化课都忘记了 正难则反!!!!!!!! 害没关系啦,一共拿到了\( ...
- 【GDOI2016模拟3.15】基因合成(回文串+性质+DP)
[GDOI2016模拟3.15]基因合成 题意: 给一个目标串,要求从空串进行最少的操作次数变成目标串,操作有两种: 在串的头或尾加入一个字符. 把串复制一遍后反向接到串的末尾. 因为有回文操作,所以 ...
- Tencent Cloud Developers Conference(2018.12.15)
时间:2018.12.15地点:北京朝阳悠唐皇冠假日酒店
随机推荐
- 剑指offer——05重建二叉树
题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7, ...
- Day 13 : 函数递归,
从前有有座山,山里有座庙,庙里有个老和尚给小和尚们讲故事,讲的什么呀,讲的是,从前有有座山,山里有座庙,庙里有个老和尚给小和尚们讲故事,讲的什么呀?讲的是?...... 递归:1.一个函数再内部调用了 ...
- WebService接口测试
- NFS服务器简易安装
1.服务端 创建挂载目录 # mkdir /data/nfs 安装NFS软件 # yum install nfs-utils -y 添加配置信息 # vim /etc/exports /data/nf ...
- 《创新者》读书笔记 PB16110698 第五周(~4.5)
本周我阅读了某同学推荐的<创新者>,这本书实际上是两个世纪以来信息技术的编年史,从巴贝奇的差分机到如今互联网时代的超级计算机,作者通过各个时代里一位位杰出的创新者,将计算机诞生.发展.崛起 ...
- php 查看linux服务器的磁盘使用情况
- 【bug】vue同一组件使用
vue使用同一个组件渲染,进行切换过程中会存在数据保存的情况. 比如路由切换,进行渲染的页面来自同一个组件,这个时候,要在监听路由的时候,将数据重新初始化
- ubuntu切换到root用户
我们都知道使用su root命令,去切换到root权限,此时会提示输入密码,可是怎么也输不对,提示"Authentication failure", 解决办法如下 su root ...
- vue 兄弟组件的传值
handleLetterClick方法,采用emit 传递给父组件 父组件触发的方法: handleLetterChange方法: 父组件传递给子组件: CityList组件: 兄弟组件的传值可以 ...
- js获取当前网址Url
js获取当前路径并截取 var str = window.location.href;// str = 'https://localhost:8080/mark' var index = str .l ...