BZOJ4919 大根堆(动态规划+treap+启发式合并)
一个显然的dp是设f[i][j]为i子树内权值<=j时的答案,则f[i][j]=Σf[son][j],f[i][a[i]]++,f[i][a[i]+1~n]对其取max。这样是可以线段树合并的,但实在太弱了不太会。
另一种做法是考虑扩展经典的单调队列优化LIS的做法,维护子树内答案为k时最小的最大值,用平衡树维护,在父亲处启发式合并,然后将父亲处权值插入即可。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 200010
#define lson tree[k].ch[0]
#define rson tree[k].ch[1]
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<''||c>'')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int n,a[N],b[N],fa[N],p[N],root[N],t,cnt;
struct data{int to,nxt;
}edge[N<<];
struct data2{int x,p,ch[],s;
}tree[N<<];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void up(int k){tree[k].s=tree[lson].s+tree[rson].s+;}
void move(int &k,int p)
{
int t=tree[k].ch[p];
tree[k].ch[p]=tree[t].ch[!p],tree[t].ch[!p]=k,up(k),up(t),k=t;
}
void ins(int &k,int x)
{
if (k==) {k=++cnt;tree[k].x=x,tree[k].p=rand(),tree[k].s=;return;}
tree[k].s++;
if (tree[k].x<x) {ins(rson,x);if (tree[rson].p>tree[k].p) move(k,);}
else {ins(lson,x);if (tree[lson].p>tree[k].p) move(k,);}
}
void del(int &k,int x)
{
if (tree[k].x==x)
{
if (lson==||rson==) {k=lson|rson;return;}
if (tree[lson].p>tree[rson].p) move(k,),del(rson,x);
else move(k,),del(lson,x);
}
else if (tree[k].x<x) del(rson,x);
else del(lson,x);
up(k);
}
int qrank(int k,int x)
{
if (!k) return ;
if (tree[k].x>=x) return qrank(lson,x);
else return qrank(rson,x)+tree[lson].s+;
}
int find(int k,int x)
{
if (tree[lson].s+==x) return tree[k].x;
if (tree[lson].s+>x) return find(lson,x);
else return find(rson,x-tree[lson].s-);
}
void dfsins(int k,int &x)
{
if (!k) return;
ins(x,tree[k].x);
dfsins(lson,x),dfsins(rson,x);
}
int merge(int x,int y)
{
if (tree[x].s<tree[y].s) swap(x,y);
dfsins(y,x);
return x;
}
void dfs(int k)
{
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=fa[k])
{
dfs(edge[i].to);
root[k]=merge(root[k],root[edge[i].to]);
}
int x=qrank(root[k],a[k]);
if (x<tree[root[k]].s) del(root[k],find(root[k],x+));
ins(root[k],a[k]);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4919.in","r",stdin);
freopen("bzoj4919.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read();srand();
for (int i=;i<=n;i++)
{
b[i]=a[i]=read(),fa[i]=read();
addedge(fa[i],i);
}
sort(b+,b+n+);
int u=unique(b+,b+n+)-b-;
for (int i=;i<=n;i++) a[i]=lower_bound(b+,b+u+,a[i])-b;
dfs();
cout<<tree[root[]].s;
return ;
}
BZOJ4919 大根堆(动态规划+treap+启发式合并)的更多相关文章
- BZOJ4919 [Lydsy1706月赛]大根堆 【dp + 启发式合并】
题目链接 BZOJ4919 题解 链上的\(LIS\)维护一个数组\(f[i]\)表示长度为\(i\)的\(LIS\)最小的结尾大小 我们可以用\(multiset\)来维护这个数组,子树互不影响,启 ...
- 2021-06-14 BZOJ4919:大根堆
BZOJ4919:大根堆 Description: 题目描述 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你 ...
- BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)
不难...treap + 启发式合并 + 并查集 搞搞就行了 --------------------------------------------------------------------- ...
- 【bzoj2733】[HNOI2012]永无乡 Treap启发式合并
题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达 ...
- bzoj4919 大根堆
考虑二分求序列LIS的过程. g[i]表示长度为i的LIS最小以多少结尾. 对于每个数,二分寻找插入的位置来更新g数组. 放到树上也是一样,额外加上一个合并儿子的过程. 发现儿子与儿子直接是互不影响的 ...
- 【20181026T2】**图【最小瓶颈路+非旋Treap+启发式合并】
题面 [错解] 最大最小?最小生成树嘛 蛤?还要求和? 点分治? 不可做啊 写了个MST+暴力LCA,30pts,140多行 事后发现30分是给dijkstra的 woc [正解] 树上计数问题:①并 ...
- 【bzoj2733】永无乡(无旋treap启发式合并 + 并查集)
传送门 题目分析 起初每个岛都是一个平衡树, 并查集的祖先都是自己.合并两岛时,pri较小的祖先会被作为合并后的祖先, 而两颗平衡树采用启发式合并.查询k值就是基本操作. code #include& ...
- treap启发式合并
注意输入v要在建根的前面. #include <cstdio> #include <iostream> #include <algorithm> #include ...
- BZOJ4919:[Lydsy1706月赛]大根堆(set启发式合并)
Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质: ...
随机推荐
- javaWeb项目-文件下载的消息头和编码问题
一.问题: 做web项目经常提到的一个需求就是页面的文件下载,那么下载的时候在后台为什么要设置响应消息头?为什么这样设置? 二.解决: 1.例子 //设置响应的消息头response.setConte ...
- [BZOJ2738]矩阵乘法-[整体二分+树状数组]
Description 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. (N<=500,Q<=60000) Solution 考虑二分答案,问题转化为求矩阵内为1 ...
- springboot中maven加入本地jar
一.今天遇到一个问题,在使用springboot打jar的时候出现了本地依赖包打不进去的情况.然后在网上试了很多方式.这里做一个记录 二.加入本地依赖包 <dependency> < ...
- Linux系统基础网络配置老鸟精华篇
对于linux高手看似简单的网络配置问题,也许要说出所以然来也并不轻松,因此仍然有太多的初学者徘徊在门外就不奇怪了,这里,老男孩老师花了一些时间总结了这个文档小结,也还不够完善,欢迎大家补充,交流.谢 ...
- Hibernate三种状态的区分,以及save,update,saveOrUpdate,merge等的使用
Hibernate的对象有3种状态,分别为:瞬时态(Transient). 持久态(Persistent).脱管态(Detached).处于持久态的对象也称为PO(Persistence Object ...
- mybatis按datetime条件查询,参数为时间戳时
mybatis按datetime条件查询,参数为时间戳时,如果数据库为2018-1-1 20:22:10, 你的时间戳也为2018-1-1 20:22:10,但却没找到数据.可能是时差导致的.百度修正 ...
- Codeforces Round #503 (by SIS, Div. 2) D. The hat
有图可以直观发现,如果一开始的pair(1,1+n/2)和pair(x, x+n/2)大小关系不同 那么中间必然存在一个答案 简单总结就是大小关系不同,中间就有答案 所以就可以使用二分 #includ ...
- NO--10今天带大家回忆回忆“闭包”吧!
对于‘闭包,我相信很多人都掉进过这个坑里,也相信很多人没能详细的理解这个问题,今天带大家再次走进闭包: 写这篇文章时的心情是十分忐忑的,因为对于我们今天的主角:闭包,很多小伙伴都写过关于它的文章,相信 ...
- 牛客网暑期ACM多校训练营(第四场):A Ternary String(欧拉降幂)
链接:牛客网暑期ACM多校训练营(第四场):A Ternary String 题意:给出一段数列 s,只包含 0.1.2 三种数.每秒在每个 2 后面会插入一个 1 ,每个 1 后面会插入一个 0,之 ...
- Python科学计算库灬numpy
Numpy NumPy是一个功能强大的Python库,主要用于对多维数组执行计算.Numpy许多底层函数实际上是用C编写的,因此它的矩阵向量计算速度是原生Python中无法比拟的. numpy属性 维 ...