zoukankan      html  css  js  c++  java
  • bzoj 4825: [Hnoi2017]单旋 LCT

    题目大意:

    维护一颗初始为空的单旋Splay,支持五种操作:

    1. 插入一个值并查询所插入的值所在的Splay节点的深度.
    2. 查询最小值所在的Splay节点的深度并将其Splay节点单旋至根.
    3. 查询最大值所在的Splay节点的深度并将其Splay节点单旋至根.
    4. 查询最小值所在的Splay节点的深度并将其Splay节点单旋至根并删除.
    5. 查询最大值所在的Splay节点的深度并将其Splay节点单旋至根并删除.

    根的深度为1,保证插入的值互不相同,保证所有操作合法.
    m <= 100000

    题解:

    直接维护这么一颗单旋Splay的做法一定被出题人叉掉了.

    首先这道题的Splay有一个特点 : 一定只会对最值进行Splay
    也就是说 : 任何时候的单次Splay里,要么只有zig,要么只要zag
    我们模拟一下操作的过程,发现 :

    然后就很明显了.
    每一次只有常数个点的父子关系变化.其余大部分点的结构均不改变.
    所以我们可以手动处理父子关系变化的节点.
    然后我们需要在树的形态不断变化的情况下动态查询某个点到根的距离.
    这样可以处理掉2,3,4,5操作,那么对于操作1怎么处理?
    我们知道一个数被插入后要么成为这个数的前驱的右儿子要么成为这个数后继的左儿子.
    对于具体成为哪个的儿子就判一下找出来的前驱/后继节点中哪个节点的儿子空着就好了
    肯定不可能出现两个节点的儿子都是空着的
    所以我们还要查询一个节点的左儿子和右儿子是否存在和分别是谁.
    至于这个查询我们直接在LCT的节点上暴力维护就好了.
    由于每次树的形态改变极小,所以也可以直接手动维护.

    听说这道题还可以ETT维护还可以Splay维护dfs序还可以Treap维护括号序列
    ... ...还有说这是线段树好题的... ...
    我只会LCT ...

    #include <set>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    inline void read(int &x){
    	x=0;char ch;bool flag = false;
    	while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    	while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
    }
    #define rg register int
    #define rep(i,a,b) for(rg i=(a);i<=(b);++i)
    #define per(i,a,b) for(rg i=(a);i>=(b);--i)
    const int maxn = 100010;
    struct Node{
    	Node *ch[2],*fa;
    	Node *lson,*rson;
    	int siz;
    	void update(){
    		siz = ch[0]->siz + ch[1]->siz + 1;
    	}
    }*null,mem[maxn],*it;
    inline void init(){
    	it = mem;null = it++;
    	null->ch[0] = null->ch[1] = null->fa = null;
    	null->siz = 0;
    	null->lson = null->rson = null;
    }
    inline Node* newNode(){
    	Node *p = it++;p->ch[0] = p->ch[1] = p->fa = null;
    	p->siz = 1;p->lson = p->rson = null;return p;
    }
    inline void rotate(Node *p,Node *x){
    	int k = p == x->ch[1];
    	Node *y = p->ch[k^1],*z = x->fa;
    	if(z->ch[0] == x) z->ch[0] = p;
    	if(z->ch[1] == x) z->ch[1] = p;
    	if(y != null) y->fa = x;
    	p->fa = z;p->ch[k^1] = x;
    	x->fa = p;x->ch[k] = y;
    	x->update();p->update();
    }
    inline bool isroot(Node *p){
    	return (p == null) || (p->fa->ch[0] != p && p->fa->ch[1] != p);
    }
    inline void Splay(Node *p){
    	while(!isroot(p)){
    		Node *x = p->fa,*y = x->fa;
    		if(isroot(x)) rotate(p,x);
    		else if( (p == x->ch[0])^(x == y->ch[0]) ) rotate(p,x),rotate(p,y);
    		else rotate(x,y),rotate(p,x);
    	}p->update();
    }
    inline void Access(Node *x){
    	for(Node *y = null;x != null;y = x,x = x->fa){
    		Splay(x),x->ch[1] = y,x->update();
    	}
    }
    struct data{
    	Node *p;
    	int key;
    	data(Node* a,const int &b){
    		p = a;key = b;
    	}
    	friend bool operator < (const data &a,const data &b){
    		return a.key < b.key;
    	}
    };
    set<data>S;
    Node *RT;
    inline int insert(int val){
    	Node *p = newNode();data x(p,val);
    	set<data>::iterator it = S.lower_bound(x);
    	int dep = 0;
    	if(it != S.end()){
    		if(it->p->lson == null){
    			it->p->lson = p;
    			p->fa = it->p;
    			Access(it->p);Splay(it->p);
    			dep = it->p->siz;
    		}
    	}
    	if(it != S.begin()){
    		-- it;
    		if(it->p->rson == null){
    			it->p->rson = p;
    			p->fa = it->p;
    			Access(it->p);Splay(it->p);
    			dep = it->p->siz;
    		}
    	}
    	if(S.empty()) RT = p;
    	S.insert(x);
    	return dep + 1;
    }
    inline int find_min(){
    	Node *p = S.begin()->p;
    	Access(p);Splay(p);
    	int ret = p->siz;
    	if(ret == 1) return ret;
    	Node *y = p->ch[0],*x = p->rson;
    	while(y->ch[1] != null) y = y->ch[1];
    	y->lson = x;p->rson = RT;
    	p->ch[0]->fa = null;
    	p->ch[0] = null;
    	p->update();
    	if(x != null) Splay(x),x->fa = y;
    	Access(RT);Splay(RT);RT->fa = p;
    	RT = p;
    	return ret;
    }
    inline int find_max(){
    	Node *p = S.rbegin()->p;
    	Access(p);Splay(p);
    	int ret = p->siz;
    	if(ret == 1) return ret;
    	Node *y = p->ch[0],*x = p->lson;
    	while(y->ch[1] != null) y = y->ch[1];
    	y->rson = x;p->lson = RT;
    	p->ch[0]->fa = null;
    	p->ch[0] = null;
    	p->update();
    	if(x != null) Splay(x),x->fa = y;
    	Access(RT);Splay(RT);RT->fa = p;
    	RT = p;
    	return ret;
    }
    inline int del_min(){
    	Node *p = S.begin()->p;
    	Access(p);Splay(p);
    	int ret = p->siz;
    	if(ret == 1){
    		Node *x = p->rson;
    		if(x != null) Splay(x),x->fa = null;
    		RT = x;
    		S.erase(S.begin());
    		return ret;
    	}
    	Node *x = p->rson,*y = p->ch[0];
    	while(y->ch[1] != null) y = y->ch[1];
    	y->lson = x;
    	p->ch[0]->fa =null;
    	p->ch[0] = null;
    	if(x != null) Splay(x),x->fa = y;
    	S.erase(S.begin());
    	return ret;
    }
    inline int del_max(){
    	Node *p = S.rbegin()->p;
    	 Access(p);Splay(p);
    	int ret = p->siz;
    	if(ret == 1){
    		Node *x = p->lson;
    		if(x != null) Splay(x),x->fa = null;
    		RT = x;
    		S.erase(*S.rbegin());
    		return ret;
    	}
    	Node *x = p->lson,*y = p->ch[0];
    	while(y->ch[1] != null) y = y->ch[1];
    	y->rson = x;
    	p->ch[0]->fa = null;
    	p->ch[0] = null;
    	if(x != null) Splay(x),x->fa = y;
    	S.erase(*S.rbegin());
    	return ret;
    }
    int main(){
    	init();
    	int m;read(m);
    	int c,k;
    	while(m--){
    		read(c);
    		if(c == 1){
    			read(k);
    			printf("%d
    ",insert(k));
    		}else if(c == 2) printf("%d
    ",find_min());
    		else if(c == 3) printf("%d
    ",find_max());
    		else if(c == 4) printf("%d
    ",del_min());
    		else if(c == 5) printf("%d
    ",del_max());
    	}
    	return 0;
    }
    
  • 相关阅读:
    de4dot 反混淆
    GreyMagic
    HearthBuddy 第一次调试
    dnSpy
    asp.net form submit 在Chrome里面看Form提交
    关于并发模型 Actor 和 CSP
    Go语言并发机制初探
    CyclicBarrier的工作原理及其实例
    Java并发编程--CyclicBarrier
    CountDownLatch的简单理解
  • 原文地址:https://www.cnblogs.com/Skyminer/p/6729786.html
Copyright © 2011-2022 走看看