[BZOJ3173][Tjoi2013]最长上升子序列

试题描述

给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?

输入

第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)

输出

N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。

输入示例

  

输出示例


数据规模及约定

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]最长上升子序列的更多相关文章

  1. bzoj3173[Tjoi2013]最长上升子序列 平衡树+lis

    3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2253  Solved: 1136[Submit][S ...

  2. bzoj3173: [Tjoi2013]最长上升子序列(树状数组+二分倒推)

    3173: [Tjoi2013]最长上升子序列 题目:传送门 题解:  好题! 怎么说吧...是应该扇死自己...看错了两次题: 每次加一个数的时候,如果当前位置有数了,是要加到那个数的前面,而不是直 ...

  3. BZOJ3173 TJOI2013最长上升子序列(Treap+ZKW线段树)

    传送门 Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input ...

  4. bzoj千题计划316:bzoj3173: [Tjoi2013]最长上升子序列(二分+树状数组)

    https://www.lydsy.com/JudgeOnline/problem.php?id=3173 插入的数是以递增的顺序插入的 这说明如果倒过来考虑,那么从最后一个插入的开始删除,不会对以某 ...

  5. BZOJ3173:[TJOI2013]最长上升子序列(Splay)

    Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input 第一行一 ...

  6. bzoj3173: [Tjoi2013]最长上升子序列(fhqtreap)

    这题用fhqtreap可以在线. fhqtreap上维护以i结尾的最长上升子序列,数字按从小到大加入, 因为前面的数与新加入的数无关, 后面的数比新加入的数小, 所以新加入的数对原序列其他数的值没有影 ...

  7. BZOJ3173 TJOI2013最长上升子序列(splay)

    容易发现如果求出最后的序列,只要算一下LIS就好了.序列用平衡树随便搞一下,这里种一棵splay. #include<iostream> #include<cstdio> #i ...

  8. 【LG4309】【BZOJ3173】[TJOI2013]最长上升子序列

    [LG4309][BZOJ3173][TJOI2013]最长上升子序列 题面 洛谷 BZOJ 题解 插入操作显然用平衡树就行了 然后因为后面的插入对前面的操作无影响 就直接在插入完的序列上用树状数组求 ...

  9. BZOJ 3173: [Tjoi2013]最长上升子序列

    3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1524  Solved: 797[Submit][St ...

随机推荐

  1. 发布和运行HOLOLENS程序注意这里要勾上,不然就成普通的UWP程序了!

  2. 字符加密Cipher(bzoj 1031)

    Description 喜欢钻研问题的JS同学,最近又迷上了对加密方法的思考.一天,他突然想出了一种他认为是终极的加密办法 :把需要加密的信息排成一圈,显然,它们有很多种不同的读法.例如下图,可以读作 ...

  3. Jsoup开发网站客户端第二篇,图片轮播,ScrollView兼容ListView

    最近一段日子忙的焦头烂额,代码重构,新项目编码,导致jsoup开发网站客户端也没时间继续下去,只能利用晚上时间去研究了.今天实现美食网首页图片轮播效果,网站效果图跟Android客户端实现如图: 从浏 ...

  4. C#和C实现通过CRC-16 (Modbus)获取CRC值并校验数据(代码)

    文章首发于浩瀚先森博客 CRC的全称为Cyclic Redundancy Check,中文名称为循环冗余校验.它是一类重要的线性分组码,编码和解码方法简单,检错和纠错能力强,在通信领域广泛地用于实现差 ...

  5. 浅谈Struts2

    学过SSH框架很长一段时间了,一直没有很系统的总结一下,这里先简单谈谈Struts2. 为什么要用Struts2? 这里列举一些Servlet的缺点: 1.每写一个servlet在web.xml中都要 ...

  6. CSS基本知识1-CSS基本概念

    CSS基本概念: 选择器{属性:值;属性:值} CSS继承:子元素继承父元素样式,父子关系看DOM结构. CSS覆盖: 浏览器缺省设置 外部样式表 内部样式表(位于 <head> 标签内部 ...

  7. 84 tune2fs-调整系统参数

    tune2fs命令允许系统管理员调整"ext2/ext3"文件系统中的可该参数.Windows下面如果出现意外断电死机情况,下次开机一般都会出现系统自检.Linux系统下面也有文件 ...

  8. Django登录访问限制 login_requeired

    作用: 1. 用户登录之后才可以访问某些页面 2. 如果没登录,跳转到登录页面 3. 用户在跳转的登陆界面中完成登陆后,自动访问跳转到之前访问的地址 要实现这个需求很简单就是在相应的view前面使用装 ...

  9. ipvsadm命令

    NAME ipvsadm - Linux Virtual Server administration SYNOPSIS ipvsadm -A|E -t|u|f service-address [-s ...

  10. [转]Java compiler level does not match解决方法

    查看链接:http://jingyan.baidu.com/article/95c9d20da3ec5fec4e756186.html