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. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质: ...
随机推荐
- day4 RHCE
12.实现一个web服务器 [root@server0 ~]# yum install httpd -y [root@server0 ~]# rpm -ql httpd 查看httpd产生的配置文件 ...
- JQuery事件机制
1 事件操作 1.1 页面载入事件 $(document).ready(function(){ // 在这里写你的代码... }); 或者 $(function($) { // 你可以在这里继续使用$ ...
- html面试题总结
1.请描述一个网页从开始请求到最终显示的完整过程? 1).在浏览器中输入网址: 2).发送至DNS服务器并获得域名对应的WEB服务器的IP地址: 3).与WEB服务器简历TCP连接: 4).浏览器向W ...
- linux系统CPU内存磁盘监控发送邮件脚本
#!/bin/bashexport PATHexport LANG=zh_CN.UTF-8###top之后输入数字1,可以查看每颗CPU的情况.###先配置好mailx邮箱账号密码:#cat>/ ...
- 使用GitLab创建项目
- perf + 火焰图用法 小结
要对新服务做性能测试,分析代码热点,初识perf,做下总结 perf + 火焰图用法 perf简介 Perf (Performance Event), Linux 系统原生提供的性能分析工具, 会返回 ...
- 用EC5/EC6自定义class的区别及用法 -- Phaser3网页游戏框架
custom class EC6 自定义class class Brain extends Phaser.GameObjects.Sprite { constructor (scene, x, y ...
- 【转】lvs、nginx、haproxy转发模式优缺点总结
原文地址: https://yq.aliyun.com/ziliao/78374 一.LVS转发模式 LVS是章文嵩博士写的一个工作于四层的高可能性软件.不像后两者支持七层转发,不过也正因为其简单,所 ...
- 生成dataset的几种方式
1.常用的方式通过sparksession读取外部文件或者数据生成dataset(这里就不讲了) 注: 生成Row对象的方法提一下:RowFactory.create(x,y,z),取Row中的数据 ...
- 当git遇上中文乱码
git有个比较奇怪的问题,当目录或者文件名中出现了中文的时候,在执行git status 的时候,会返回一串unicode码,这段unicode码就读不懂了,必须解决. git status显示uni ...