zoukankan      html  css  js  c++  java
  • [BZOJ3173][Tjoi2013]最长上升子序列

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

    试题描述

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

    输入

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

    输出

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

    输入示例

    3
    0 0 2

    输出示例

    1
    1
    2

    数据规模及约定

    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
    ", 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
    ", qmx(rt, i + 1));
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    微擎二次开发
    linux
    自动自发与强制要求的差别
    金老师的经典著作《一个普通IT人的十年回顾》
    离开了公司,你还有什么
    [转]想靠写程序赚更多钱,写到两眼通红,写得比别人都又快又好好几倍,结果又能如何?
    挨踢人生路--记我的10年18家工作经历 续 .转
    论优越感
    当程序员的那些狗日日子-----转载
    C#语法杂谈
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6204729.html
Copyright © 2011-2022 走看看