[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. js中的按键事件

    参考链接:http://blog.csdn.net/zhouziyu2011/article/details/53978293 <input type="text" id=& ...

  2. mysql apach php

    一.MySql MySQL安装文件分为两种,一种是msi格式的,一种是zip格式的.如果是msi格式的可以直接点击安装,按照它给出的安装提示进行安装(相信大家的英文可以看懂英文提示),一般MySQL将 ...

  3. jquery获取父元素及祖先元素

    parent是找当前元素的第一个父节点,parents是找当前元素的所有父节点 先说一下parent和parents的区别 从字面上不难看出 parent是指取得一个包含着所有匹配元素的唯一父元素的元 ...

  4. Showbo.Msg.alert

    注意alert,confirm及prompt并不同于系统的,这个是用层模仿的,并不能挂起程序的执行 所以如果需要在确认后执行相关的操作,需要在配置文件中传递回调函数fn 按钮只提供yes和no两个 S ...

  5. Android 高清加载巨图方案 拒绝压缩图片

    Android 高清加载巨图方案 拒绝压缩图片 转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/49300989: 本文出自:[张 ...

  6. [masmplus]初次使用报external symbol _start 是配置问题

    初次使用masmplus 其中在 codesg segment 使用了 start 标记, 并在end处标明了:end  start  但是默认的masmplus 会提示 start 为 不认识的 e ...

  7. Unix NetWork Programming(unix环境编程)——环境搭建(解决unp.h等源码编译问题)

    此配置实例亲测成功,共勉,有问题大家留言. 环境:VMware 10 + unbuntu 14.04 为了unix进行网络编程,编程第一个unix程序时遇到的问题,不能包含unp.h文件,这个感觉和a ...

  8. 格雷码原理与Verilog实现

    格雷码原理 格雷码是一个叫弗兰克*格雷的人在1953年发明的,最初用于通信.格雷码是一种循环二进制码或者叫作反射二进制码.格雷码的特点是从一个数变为相邻的一个数时,只有一个数据位发生跳变,由于这种特点 ...

  9. 在c#中使用指针

    如果想在c#中使用指针,首先对项目进行配置:在解决方案资源管理器中右击项目名选择属性(或在项目菜单中选择consoleApplication属性(consoleApplication为项名)),在生成 ...

  10. Python学习之day2

    1.执行Python脚本时打印的字符有颜色 print "\033[32;1mhello\033[0m" #打印绿色 print "\033[31;1mhello\033 ...