[BZOJ3173][Tjoi2013]最长上升子序列
[BZOJ3173][Tjoi2013]最长上升子序列
试题描述
输入
输出
输入示例
输出示例
数据规模及约定
100%的数据 n<=100000
题解
首先讲一下怎么找到插入的位置,不难发现输入的数 k 就是让我们找到一个位置使得该位置左边有 k 个数然后在这个位置上插入。这不就是“第 k 大数”问题么?
好的,在此基础之上,我们再在 treap 上维护一波子树最大权值即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 100010
struct Node {
int r, val, mx, siz;
Node() {}
Node(int _, int __): r(_), val(__) {}
} ns[maxn];
int rt, ToT, fa[maxn], ch[2][maxn];
void maintain(int o) {
ns[o].mx = ns[o].val; ns[o].siz = 1;
for(int i = 0; i < 2; i++) if(ch[i][o])
ns[o].mx = max(ns[o].mx, ns[ch[i][o]].mx),
ns[o].siz += ns[ch[i][o]].siz;
return ;
}
void rotate(int u) {
int y = fa[u], z = fa[y], l = 0, r = 1;
if(z) ch[ch[1][z]==y][z] = u;
if(ch[1][y] == u) swap(l, r);
fa[u] = z; fa[y] = u; fa[ch[r][u]] = y;
ch[l][y] = ch[r][u]; ch[r][u] = y;
maintain(y); maintain(u);
return ;
}
void insert(int& o, int k, int val) {
if(!o) {
ns[o = ++ToT] = Node(rand(), val);
return maintain(o);
}
int ls = ch[0][o] ? ns[ch[0][o]].siz : 0;
bool d = (k >= ls + 1);
insert(ch[d][o], k - (ls + 1) * d, val); fa[ch[d][o]] = o;
if(ns[ch[d][o]].r > ns[o].r) {
int t = ch[d][o];
rotate(t); o = t;
}
return maintain(o);
}
int Find(int o, int k) {
if(!o) return 0;
int lm = ch[0][o] ? ns[ch[0][o]].mx : 0, ls = ch[0][o] ? ns[ch[0][o]].siz : 0;
if(k >= ls + 1) return max(max(lm, ns[o].val), Find(ch[1][o], k - ls - 1));
return Find(ch[0][o], k);
} int main() {
int n = read();
for(int i = 1; i <= n; i++) {
int p = read(), v = Find(rt, p);
insert(rt, p, v + 1);
printf("%d\n", ns[rt].mx);
} return 0;
}
替罪羊树版:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
} #define maxn 100010
struct Node {
int v, siz, mx;
Node() {}
Node(int _): v(_) {}
} ns[maxn];
int rt, ToT, fa[maxn], ch[maxn][2];
void maintain(int o) {
ns[o].siz = 1; ns[o].mx = ns[o].v;
for(int i = 0; i < 2; i++) if(ch[o][i])
ns[o].siz += ns[ch[o][i]].siz,
ns[o].mx = max(ns[o].mx, ns[ch[o][i]].mx);
return ;
}
const double Bili = .6;
bool unbal(int o) {
return max(ch[o][0] ? ns[ch[o][0]].siz : 0, ch[o][1] ? ns[ch[o][1]].siz : 0) > Bili * ns[o].siz;
}
int rb;
void insert(int& o, int k, int v) {
if(!o) {
ns[o = ++ToT] = Node(v);
return maintain(o);
}
int ls = ch[o][0] ? ns[ch[o][0]].siz : 0;
if(k < ls + 1) insert(ch[o][0], k, v), fa[ch[o][0]] = o;
else insert(ch[o][1], k - ls - 1, v), fa[ch[o][1]] = o;
maintain(o);
if(unbal(o)) rb = o;
return ;
}
int cntn, get[maxn];
void getnode(int o) {
if(!o) return ;
getnode(ch[o][0]);
get[++cntn] = o;
getnode(ch[o][1]);
fa[o] = ch[o][0] = ch[o][1] = 0;
return ;
}
void build(int& o, int l, int r) {
if(l > r) return ;
int mid = l + r >> 1; o = get[mid];
build(ch[o][0], l, mid - 1); build(ch[o][1], mid + 1, r);
if(ch[o][0]) fa[ch[o][0]] = o;
if(ch[o][1]) fa[ch[o][1]] = o;
return maintain(o);
}
void rebuild(int& o) {
cntn = 0; getnode(o);
build(o, 1, cntn);
return ;
}
void Insert(int k, int v) {
rb = 0; insert(rt, k, v);
if(!rb) return ;
int frb = fa[rb];
if(!frb) rebuild(rt), fa[rt] = 0;
else if(ch[frb][0] == rb) rebuild(ch[frb][0]), fa[ch[frb][0]] = frb;
else rebuild(ch[frb][1]), fa[ch[frb][1]] = frb;
return ;
}
int qmx(int o, int k) {
if(!o) return 0;
int ls = ch[o][0] ? ns[ch[o][0]].siz : 0, lm = ch[o][0] ? ns[ch[o][0]].mx : 0;
if(k < ls + 1) return qmx(ch[o][0], k);
return max(max(lm, ns[o].v), qmx(ch[o][1], k - ls - 1));
} int main() {
int n = read();
for(int i = 1; i <= n; i++) {
int pos = read(), tmp = qmx(rt, pos);
Insert(pos, tmp + 1);
printf("%d\n", qmx(rt, i + 1));
} return 0;
}
[BZOJ3173][Tjoi2013]最长上升子序列的更多相关文章
- bzoj3173[Tjoi2013]最长上升子序列 平衡树+lis
3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2253 Solved: 1136[Submit][S ...
- bzoj3173: [Tjoi2013]最长上升子序列(树状数组+二分倒推)
3173: [Tjoi2013]最长上升子序列 题目:传送门 题解: 好题! 怎么说吧...是应该扇死自己...看错了两次题: 每次加一个数的时候,如果当前位置有数了,是要加到那个数的前面,而不是直 ...
- BZOJ3173 TJOI2013最长上升子序列(Treap+ZKW线段树)
传送门 Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input ...
- bzoj千题计划316:bzoj3173: [Tjoi2013]最长上升子序列(二分+树状数组)
https://www.lydsy.com/JudgeOnline/problem.php?id=3173 插入的数是以递增的顺序插入的 这说明如果倒过来考虑,那么从最后一个插入的开始删除,不会对以某 ...
- BZOJ3173:[TJOI2013]最长上升子序列(Splay)
Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input 第一行一 ...
- bzoj3173: [Tjoi2013]最长上升子序列(fhqtreap)
这题用fhqtreap可以在线. fhqtreap上维护以i结尾的最长上升子序列,数字按从小到大加入, 因为前面的数与新加入的数无关, 后面的数比新加入的数小, 所以新加入的数对原序列其他数的值没有影 ...
- BZOJ3173 TJOI2013最长上升子序列(splay)
容易发现如果求出最后的序列,只要算一下LIS就好了.序列用平衡树随便搞一下,这里种一棵splay. #include<iostream> #include<cstdio> #i ...
- 【LG4309】【BZOJ3173】[TJOI2013]最长上升子序列
[LG4309][BZOJ3173][TJOI2013]最长上升子序列 题面 洛谷 BZOJ 题解 插入操作显然用平衡树就行了 然后因为后面的插入对前面的操作无影响 就直接在插入完的序列上用树状数组求 ...
- BZOJ 3173: [Tjoi2013]最长上升子序列
3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1524 Solved: 797[Submit][St ...
随机推荐
- 数据库_MYSQL
数据库简介 数据库分类:关系型数据库.非关系型数据库 常用的关系型数据库有:orcale .mysql .sql server等等 常用的非关系型数据库有: Memcached.redis.mong ...
- sublime text nodejs set
把新建的system清空,输入{ "cmd": ["node", "$file"], "selector": " ...
- 使用gulp工具生成svgsprites
简介 SVG即可缩放矢量图形 (Scalable Vector Graphics)的简称, 是一种用来描述二维矢量图形的XML标记语言. SVG图形不依赖于分辨率, 因此图形不会因为放大而显示出明显的 ...
- javaScript中的页面传值
function getURIParam(name) { var search = window.location.search; search = search.substring(1); if ( ...
- linux 代码分析工具 gprof - 以wpa_supplicant为例
当我们遇到一个新的程序的时候,经常会无从下手,需要debug一个功能的时候,我们不知道函数的运行流程是怎么样的,这就需要借助工具来帮助我们加快流程了.这里以分析wpa_supplicant为例 ...
- 【三石jQuery视频教程】01.图片循环展示_再次重发
之前的文章,由于在博文的底部放有微信公众号的缘故,被管理员判定为: 您好,您的这篇博文内容本身没什么问题,但是,在博文底部存在推广信息内容.... 你们也没告知到底是哪条触犯了博客园的规矩,我就把底部 ...
- 容器化redis高可用方案
偶然看到一个GITHUB项目,提供了一套Docker Compose下的redis Sentinel方案. 项目地址https://github.com/AliyunContainerService/ ...
- SQLite剖析之动态内存分配
SQLite通过动态内存分配来获取各种对象(例如数据库连接和SQL预处理语句)所需内存.建立数据库文件的内存Cache.保存查询结果. 1.特性 SQLite内核和它的内存分配子系统提供以下特性 ...
- ADC
ADC转换分为两种通道组 1.规则通道组 2.注入通道组(可打断规则通道组) 工作模式 通道模式 转换模式 复位校准 AD校准
- URL类
java.net.URL类是对统一资源定位符(如http://www.lolcats.com)的抽象.它扩展了java.lang.Object,是一个final类.它采用策略模式,协议处理器(prot ...