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

时间:2022-12-22 20:27:32

[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&lbrack;Tjoi2013&rsqb;最长上升子序列 平衡树&plus;lis

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

  2. bzoj3173&colon; &lbrack;Tjoi2013&rsqb;最长上升子序列&lpar;树状数组&plus;二分倒推&rpar;

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

  3. BZOJ3173 TJOI2013最长上升子序列&lpar;Treap&plus;ZKW线段树&rpar;

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

  4. bzoj千题计划316:bzoj3173&colon; &lbrack;Tjoi2013&rsqb;最长上升子序列(二分&plus;树状数组)

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

  5. BZOJ3173&colon;&lbrack;TJOI2013&rsqb;最长上升子序列&lpar;Splay&rpar;

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

  6. bzoj3173&colon; &lbrack;Tjoi2013&rsqb;最长上升子序列(fhqtreap)

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

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

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

  8. 【LG4309】【BZOJ3173】&lbrack;TJOI2013&rsqb;最长上升子序列

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

  9. BZOJ 3173&colon; &lbrack;Tjoi2013&rsqb;最长上升子序列

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

随机推荐

  1. Oracle Sales Cloud:报告和分析(BIEE)小细节2——利用变量和过滤器传参(例如,根据提示展示不同部门的数据)

    在上一篇随笔中,我们建立了部门和子部门的双提示,并将部门和子部门做了关联.那么,本篇随笔我们重点介绍利用建好的双提示进行传参. 在操作之前,我们来看一个报告和分析的具体需求: [1] 两个有关联的提示 ...

  2. log4net 2&period;0&period;4有问题,AdoNetAppender会报错

    坑死老子了 <appSettings> <add key="log4net.Internal.Debug" value="true"/> ...

  3. Cassandra 介绍

    cassandra是一种NoSQL数据库,No是指No Relational.cassandra的数据模型结合了Dynamo的key/value和BigTable  的面向列的特点,主要被设计为存储大 ...

  4. Lowest Common Ancestor of a Binary Tree

    Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According ...

  5. iOS文件存储路径规定

    Storing Your App’s Data Efficiently https://developer.apple.com/icloud/documentation/data-storage/in ...

  6. MySQL校对规则(三)

    校对规则:在当前编码下,字符之间的比较顺序是什么? ci:不区分大小写,Cs区分大小写, _bin 编码比较 每个字符集都支持不定数量的校对规则,可以通过如下指令: show collation 可以 ...

  7. 初步理解MVC

    一.Asp.net WebForms 与Asp.net MVC 概念 Asp.net是创建WEB应用的框架,MVC是能够用更好的方法来组织并管理代码的一种更高级架构体系. 我们可将原来的Asp.net ...

  8. &lbrack;React Flow&rsqb; Up and Running with Facebook Flow for Typed JavaScript

    Install: npm i -D flow-binnpm i -g flow-bin Init: flow init Script: "typecheck": "flo ...

  9. Svn入门

    1.建立svn仓库 ›    命令svnadmin create 仓库名称,如:进入命令行窗口,切换到Svn安装目录下,输入如下命令:svnadmin create F:\software\repos ...

  10. nginx随着passenger构造ruby on rails页

    1.备份nginx简介 cp /opt/nginx/html/nginx.conf /opt/nginx/html/nginx.conf.bak 2.编者nginx简介 server { listen ...