• 【LG3721】[HNOI2017]单旋


    【LG3721】[HNOI2017]单旋

    题面

    洛谷

    题解

    20pts

    直接模拟(spaly)的过程即可。

    100pts

    可以发现单旋最大、最小值到根,手玩是有显然规律的,发现只需要几次(link,cut),那么我们维护原树的父子关系以及一颗(LCT)

    对于插入操作,由于插入的值肯定在前驱的右儿子或后继的左儿子,用(set)维护前驱后继即可。

    建议自己独立找出规律,这里不再赘述,这题其实细节还是挺多的。

    代码

    #include <iostream> 
    #include <cstdio> 
    #include <cstdlib> 
    #include <cstring> 
    #include <cmath> 
    #include <algorithm>
    #include <set>
    #include <map> 
    using namespace std; 
    inline int gi() { 
        register int data = 0, w = 1; 
        register char ch = 0; 
        while (!isdigit(ch) && ch != '-') ch = getchar(); 
        if (ch == '-') w = -1, ch = getchar(); 
        while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); 
        return w * data; 
    }
    const int MAX_N = 2e5 + 5; 
    struct Node { int ch[2], fa, size; bool rev; } t[MAX_N]; 
    struct Clone { int v, ls, rs, fa; } _t[MAX_N]; 
    int root, tot; 
    bool get(int x) { return t[t[x].fa].ch[1] == x; } 
    bool nroot(int x) { return t[t[x].fa].ch[0] == x || t[t[x].fa].ch[1] == x; } 
    void pushup(int x) { t[x].size = t[t[x].ch[0]].size + t[t[x].ch[1]].size + 1; } 
    void putrev(int x) { swap(t[x].ch[0], t[x].ch[1]); t[x].rev ^= 1; } 
    void pushdown(int x) { 
    	if (!t[x].rev) return ; 
    	if (t[x].ch[0]) putrev(t[x].ch[0]); 
    	if (t[x].ch[1]) putrev(t[x].ch[1]); 
    	t[x].rev = 0; 
    } 
    void rotate(int x) { 
    	int y = t[x].fa, z = t[y].fa, k = get(x); 
    	if (nroot(y)) t[z].ch[get(y)] = x; 
    	t[x].fa = z; 
    	t[t[x].ch[k ^ 1]].fa = y, t[y].ch[k] = t[x].ch[k ^ 1]; 
    	t[y].fa = x, t[x].ch[k ^ 1] = y; 
    	pushup(y), pushup(x); 
    } 
    void splay(int x) { 
    	static int stk[MAX_N], top; 
    	stk[top = 1] = x; 
    	for (int i = x; nroot(i); i = t[i].fa) stk[++top] = t[i].fa; 
    	for (int i = top; i; --i) pushdown(stk[i]); 
    	while (nroot(x)) { 
    		int y = t[x].fa; 
    		if (nroot(y)) get(x) ^ get(y) ? rotate(x) : rotate(y); 
    		rotate(x); 
    	} 
    } 
    void access(int x) { for (int y = 0; x; y = x, x = t[x].fa) splay(x), t[x].ch[1] = y, pushup(x); } 
    void makeroot(int x) { access(x); splay(x); putrev(x); } 
    void link(int x, int y) { makeroot(x); t[x].fa = y; } 
    void split(int x, int y) { makeroot(x); access(y); splay(y); } 
    void cut(int x, int y) { split(x, y); t[x].fa = t[y].ch[0] = 0; pushup(y); }
    set<int> st; 
    map<int, int> mp; 
    void insert(int v) { 
    	int x = ++tot; 
    	mp[v] = x, _t[x].v = v; 
    	if (st.size() == 0) return st.insert(v), root = x, (void)puts("1"); 
    	set<int> :: iterator ite = st.upper_bound(v); 
    	if (ite == st.end() || _t[mp[*ite]].ls) { 
    		--ite; 
    		int tmp = mp[*ite]; 
    		link(x, tmp), _t[tmp].rs = x, _t[x].fa = tmp; 
    	} else { 
    		int tmp = mp[*ite]; 
    		link(x, tmp), _t[tmp].ls = x, _t[x].fa = tmp; 
    	} 
    	st.insert(v); 
    	return split(x, root), (void)printf("%d
    ", t[root].size); 
    } 
    void splay_min() { 
    	int x = mp[*st.begin()]; 
    	if (x == root) return (void)puts("1"); 
    	split(x, root); printf("%d
    ", t[root].size); 
    	cut(x, _t[x].fa); if (_t[x].rs) cut(x, _t[x].rs); 
    	link(x, root); if (_t[x].rs) link(_t[x].fa, _t[x].rs); 
    	_t[_t[x].fa].ls = _t[x].rs; if (_t[x].rs) _t[_t[x].rs].fa = _t[x].fa; 
    	_t[x].fa = 0, _t[root].fa = x, _t[x].rs = root; 
    	root = x; 
    } 
    void splay_max() {
        int x = mp[*st.rbegin()]; 
        if (x == root) return (void)puts("1"); 
        split(x, root); printf("%d
    ", t[root].size); 
        cut(x, _t[x].fa); if (_t[x].ls) cut(x, _t[x].ls); 
        link(x, root); if (_t[x].ls) link(_t[x].ls, _t[x].fa); 
        _t[_t[x].fa].rs = _t[x].ls; if (_t[x].ls) _t[_t[x].ls].fa = _t[x].fa; 
        _t[x].fa = 0, _t[root].fa = x, _t[x].ls = root; 
        root = x; 
    } 
    void del_min() {
        int x = mp[*st.begin()]; 
        if (root == x) { 
    		puts("1"); 
    		if (_t[x].rs) cut(x, _t[x].rs); 
    		_t[_t[x].rs].fa = 0, root = _t[x].rs; 
    		st.erase(st.begin()); 
    		return ;
    	} 
        split(x, root); printf("%d
    ", t[root].size);
        cut(x, _t[x].fa); if (_t[x].rs) cut(x, _t[x].rs);
        if (_t[x].rs) link(_t[x].fa, _t[x].rs);
        _t[_t[x].fa].ls = _t[x].rs; if (_t[x].rs) _t[_t[x].rs].fa = _t[x].fa; 
        st.erase(st.begin()); 
    }
    void del_max() {
        int x = mp[*st.rbegin()]; 
        if (root == x) {
    		puts("1");
    		if (_t[x].ls) cut(x, _t[x].ls);
    		_t[_t[x].ls].fa = 0, root = _t[x].ls;
    		st.erase(--st.end()); 
    		return; 
    	} 
        split(x, root); printf("%d
    ", t[root].size); 
        cut(x, _t[x].fa); if (_t[x].ls) cut(x, _t[x].ls);
        if (_t[x].ls) link(_t[x].ls, _t[x].fa);
        _t[_t[x].fa].rs = _t[x].ls; if(_t[x].ls) _t[_t[x].ls].fa = _t[x].fa; 
        st.erase(--st.end()); 
    }
    int main () {
    #ifndef ONLINE_JUDGE 
        freopen("cpp.in", "r", stdin); 
    #endif
    	int M = gi(); 
        for (int i = 1; i <= M; i++) {
            int op = gi();
            switch (op) { 
                case 1: insert(gi()); break; 
                case 2: splay_min(); break; 
                case 3: splay_max(); break; 
                case 4: del_min(); break; 
                case 5: del_max(); break; 
            } 
        } 
    	return 0; 
    } 
    
  • 相关阅读:
    vue全家桶
    uniapp——如何配置scss和uview ui框架
    uniapp——自定义input清除事件
    响应式页面中的echart
    elementui 切换下拉框值,改变验证规则prop的表单项是否为必填项
    小程序view标签内容 文本过长,自动换行的问题
    vue 中使用图片查看器插件Viewer.js
    跳转不同导航,滚动条滚回初始
    vue项目中回显当前时间的农历时间
    移动端点击导航滑动展示全部选项,以为跳转页面定位到相应位置
  • 原文地址:https://www.cnblogs.com/heyujun/p/10447559.html
Copyright © 2020-2023  润新知