一个显然的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+启发式合并)的更多相关文章

  1. BZOJ4919 [Lydsy1706月赛]大根堆 【dp + 启发式合并】

    题目链接 BZOJ4919 题解 链上的\(LIS\)维护一个数组\(f[i]\)表示长度为\(i\)的\(LIS\)最小的结尾大小 我们可以用\(multiset\)来维护这个数组,子树互不影响,启 ...

  2. 2021-06-14 BZOJ4919:大根堆

    BZOJ4919:大根堆 Description: 题目描述   给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你 ...

  3. BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)

    不难...treap + 启发式合并 + 并查集 搞搞就行了 --------------------------------------------------------------------- ...

  4. 【bzoj2733】[HNOI2012]永无乡 Treap启发式合并

    题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达 ...

  5. bzoj4919 大根堆

    考虑二分求序列LIS的过程. g[i]表示长度为i的LIS最小以多少结尾. 对于每个数,二分寻找插入的位置来更新g数组. 放到树上也是一样,额外加上一个合并儿子的过程. 发现儿子与儿子直接是互不影响的 ...

  6. 【20181026T2】**图【最小瓶颈路+非旋Treap+启发式合并】

    题面 [错解] 最大最小?最小生成树嘛 蛤?还要求和? 点分治? 不可做啊 写了个MST+暴力LCA,30pts,140多行 事后发现30分是给dijkstra的 woc [正解] 树上计数问题:①并 ...

  7. 【bzoj2733】永无乡(无旋treap启发式合并 + 并查集)

    传送门 题目分析 起初每个岛都是一个平衡树, 并查集的祖先都是自己.合并两岛时,pri较小的祖先会被作为合并后的祖先, 而两颗平衡树采用启发式合并.查询k值就是基本操作. code #include& ...

  8. treap启发式合并

    注意输入v要在建根的前面. #include <cstdio> #include <iostream> #include <algorithm> #include ...

  9. BZOJ4919:[Lydsy1706月赛]大根堆(set启发式合并)

    Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质: ...

随机推荐

  1. day6 角点检测

    1.Harris角点检测 # coding=utf-8 import cv2 import numpy as np filename = 'pic5.png' #1.读入一个灰度图像 img = cv ...

  2. 【BZOJ3110】【LG3332】[ZJOI2013]K大数查询

    [BZOJ3110][LG3332][ZJOI2013]K大数查询 题面 洛谷 BZOJ 题解 和普通的整体分治差不多 用线段树维护一下每个查询区间内大于每次二分的值\(mid\)的值即可 然后再按套 ...

  3. PHP 中call_user_func相关函数的使用

    call_user_func 官方的解释是:把第一个参数作为回调函数(callback),并且将其余的参数作为回调函数的参数. 第一个参数可以是函数名,后面的均为作为该函数使用的参数. 1. call ...

  4. java class file

    目录 什么是java类文件 幻数 主次版本号 常量池数和常量池 this_class super_class 接口数量和接口 字段数和字段 方法数和方法 以下内容主要还是参考<Inside JV ...

  5. PHP反序列化漏洞代码审计—学习资料

    1.什么是序列化 A.PHP网站的定义: 所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示.unserialize()函数能够重新把字符串变回php原来的值. ...

  6. idea scala 报 with UTF-8 Please try specifying another one using the -encoding option

    现象如下图, 代码里有汉字,执行代码报错,说编码格式不对, 修改方式如上面,将右下角的编码格式修改成 u8即可.

  7. nginx main函数

    源代码: int ngx_cdecl main(int argc, char *const *argv) { ngx_int_t i; ngx_log_t *log; ngx_cycle_t *cyc ...

  8. Hyperledger Fabric CouchDB as the State Database——使用CouchDB

    使用CouchDB作为状态数据库 状态数据库选项 状态数据库包括LevelDB和CouchDB.LevelDB是嵌入在peer进程中的默认键/值状态数据库,CouchDB是一个可选的外部状态数据库.与 ...

  9. ConcurrentHashMap(JDK1.8)为什么要放弃Segment

    今天看到一篇博客:jdk1.8的HashMap和ConcurrentHashMap,我想起了前段时间面试的一个问题:ConcurrentHashMap(JDK1.8)为什么要使用synchronize ...

  10. LibLas学习笔记

    LibLas学习笔记 las  什么是Las格式 LAS文件格式是数据用户之间交换三维点云数据的公共文件格式. 虽然这种格式主要用于交换激光雷达点云数据,但是它支持交换任何三维的x.y.z 数组. 这 ...