zoukankan      html  css  js  c++  java
  • 【题解】 [AH/HNOI2017]单旋 LCT+splay

    Legend

    Link ( extrm{to LOJ})

    维护一颗 spaly,支持一些操作并计算操作的代价:

    • 插入一个数字 (v),保证与之前不同,代价为新节点的深度;
    • 单旋最小值到根,代价为单旋前的深度;
    • 单旋最大值到根,代价为单旋前的深度;
    • 单旋并删除最小值,代价为单旋前的深度;
    • 单旋并删除最大值,代价为单旋前的深度;

    操作总数 (m le 10^5)

    Editorial

    手玩一下,发现:

    • 插入一定是选前驱或后缀深度较大那个插到儿子去。
    • 单旋最小值是把最小值右子树接到父亲去,并把最小值转到根,把整棵树接到它右子树。
    • 单旋最大值是把最大值左子树接到父亲去,并把最大值转到根,把整棵树接到它左子树。

    直接用 ( m{LCT}) 维护。

    Code

    随便用个 ( m{set}) 维护前驱后继就行了。

    代码无比冗长。

    #include <bits/stdc++.h>
    
    #define debug(...) fprintf(stderr ,__VA_ARGS__)
    #define __FILE(x)
    	freopen(#x".in" ,"r" ,stdin);
    	freopen(#x".out" ,"w" ,stdout)
    
    int read(){
    	char k = getchar(); int x = 0;
    	while(k < '0' || k > '9') k = getchar();
    	while(k >= '0' && k <= '9') x = x * 10 + k - '0' ,k = getchar();
    	return x;
    }
    
    
    int root;
    const int MX = 1e5 + 233;
    namespace LCT{
    	#define lch(x) ch[x][0]
    	#define rch(x) ch[x][1]
    	int fa[MX] ,ch[MX][2] ,rev[MX] ,size[MX];
    	int get(int x){return x == ch[fa[x]][1];}
    	int Nroot(int x){return get(x) || x == ch[fa[x]][0];}
    	void pushup(int x){size[x] = 1 + size[lch(x)] + size[rch(x)];}
    	void dorev(int x){rev[x] ^= 1; std::swap(lch(x) ,rch(x));}
    	void pushdown(int x){
    		if(rev[x]){
    			if(lch(x)) dorev(lch(x));
    			if(rch(x)) dorev(rch(x));
    			rev[x] = 0;
    		}
    	}
    	void rotate(int x){
    		int f = fa[x] ,gf = fa[f] ,which = get(x) ,W = ch[x][!which];
    		if(Nroot(f)) ch[gf][get(f)] = x;
    		ch[x][!which] = f ,ch[f][which] = W;
    		if(W) fa[W] = f;
    		fa[f] = x ,fa[x] = gf ,pushup(f) ,pushup(x);
    	}
    
    	int stk[MX] ,dep;
    	void splay(int x){
    		int f = x; stk[++dep] = f;
    		while(Nroot(f)) stk[++dep] = f = fa[f];
    		while(dep) pushdown(stk[dep--]);
    		while(Nroot(x)){
    			if(Nroot(f = fa[x]))  rotate(get(x) == get(f) ? f : x);
    			rotate(x);
    		}pushup(x);
    	}
    	void access(int x){
    		for(int y = 0 ; x ; x = fa[y = x])
    			splay(x) ,rch(x) = y ,pushup(x);
    	}
    	void makeroot(int x){access(x) ,splay(x) ,dorev(x);}
    	int qdep(int x){access(x) ,splay(root); return size[root];}
    	void link(int f ,int son){
    		makeroot(son);
    		fa[son] = f;
    		// debug("link %d %d
    " ,f ,son);
    	}
    	void cut(int x ,int y){
    		// debug("cut %d %d
    " ,x ,y);
    		makeroot(x) ,access(y) ,splay(x);
    		rch(x) = fa[y] = 0; pushup(x);
    	}
    	#undef lch
    	#undef rch
    }using namespace LCT;
    
    struct number{
    	int value ,id;
    	number(int v ,int _id = -1){value = v ,id = _id;}
    	bool operator <(const number &B)const{
    		return value < B.value;
    	}
    };
    
    int tr[MX][2] ,pa[MX];
    
    std::set<number> cur;
    
    void spaly_min(){
    	auto aim = cur.begin();
    	if(cur.size() == 1) return;
    	
    	int x = aim->id;
    	printf("%d
    " ,qdep(aim->id));
    	if(root != x && tr[x][1]){
    		pa[tr[x][1]] = pa[x];
    		tr[pa[x]][0] = tr[x][1];
    		cut(x ,tr[x][1]);
    		cut(pa[x] ,x);
    		link(pa[x] ,tr[x][1]);
    		tr[x][1] = pa[x] = 0;
    		link(x ,root);
    		tr[x][1] = root;
    		pa[root] = x ,root = x;
    		makeroot(x);
    	}
    	else if(root != x && !tr[x][1]){
    		cut(pa[x] ,x);
    		tr[pa[x]][0] = 0;
    		pa[x] = 0;
    		link(x ,root);
    		tr[x][1] = root ,pa[root] = x ,root = x;
    		makeroot(x);
    	}
    	else{}
    	makeroot(root);
    }
    
    void spaly_max(){
    	auto aim = prev(cur.end());
    	if(cur.size() == 1) return;
    	
    	int x = aim->id;
    	printf("%d
    " ,qdep(aim->id));
    	if(root != x && tr[x][0]){
    		pa[tr[x][0]] = pa[x];
    		tr[pa[x]][1] = tr[x][0];
    		cut(x ,tr[x][0]);
    		cut(pa[x] ,x);
    		link(pa[x] ,tr[x][0]);
    		tr[x][0] = pa[x] = 0;
    		link(x ,root);
    		tr[x][0] = root;
    		pa[root] = x ,root = x;
    		makeroot(x);
    	}
    	else if(root != x && !tr[x][0]){
    		cut(pa[x] ,x);
    		tr[pa[x]][1] = 0;
    		pa[x] = 0;
    		link(x ,root);
    		tr[x][0] = root ,pa[root] = x ,root = x;
    		makeroot(x);
    	}
    	else{}
    	makeroot(root);
    }
    
    int main(){
    	__FILE(danxuan);
    	int m = read();
    	for(int I = 1 ; I <= m ; ++I){
    		debug("%d
    " ,I);
    		int op = read();
    		if(op == 1){
    			int k = read();
    			if(cur.empty()){
    				cur.insert(number(k ,I));
    				root = I;
    				printf("1
    ");
    				continue;
    			}
    			auto nxt = cur.lower_bound(k);
    			if(nxt == cur.end()){
    				--nxt;
    				tr[nxt->id][1] = I;
    				pa[I] = nxt->id;
    				link(nxt->id ,I);
    			}
    			else{
    				if(nxt == cur.begin()){
    					tr[nxt->id][0] = I;
    					pa[I] = nxt->id;
    					link(nxt->id ,I);
    				}
    				else{
    					int predep = qdep(prev(nxt)->id),
    						nxtdep = qdep(nxt->id);
    					if(predep > nxtdep){
    						--nxt;
    						tr[nxt->id][1] = I;
    						pa[I] = nxt->id;
    						link(nxt->id ,I);
    					}
    					else{
    						tr[nxt->id][0] = I;
    						pa[I] = nxt->id;
    						link(nxt->id ,I);
    					}
    				}
    			}
    			printf("%d
    " ,qdep(I));
    			cur.insert(number(k ,I));
    		}
    		if(op == 2){
    			spaly_min();
    		}if(op == 3){
    			spaly_max();
    		}if(op == 4){
    			spaly_min();
    			cur.erase(cur.begin());
    			if(root){
    				cut(root ,tr[root][1]);
    				pa[tr[root][1]] = 0;
    				root = tr[root][1];
    				makeroot(root);
    			}else root = 0;
    		}if(op == 5){
    			spaly_max();
    			cur.erase(prev(cur.end()));
    			if(root){
    				cut(root ,tr[root][0]);
    				pa[tr[root][0]] = 0;
    				root = tr[root][0];
    				makeroot(root);
    			}else root = 0;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    anaconda环境---ubuntu下重装
    算法---Face_Recognition配置实战篇
    算法---FaceNet+mtcnn的使用记录
    算法---FaceNet理论学习篇
    算法---FaceNet在Tf下的实战篇
    ubuntu系统---切换Py2.X与Py3.X版本
    anaconda环境中---py2.7下安装tf1.0 + py3.5下安装tf1.5
    Git---初入开源代码管理库的学习过程003
    day 87 Vue学习六之axios、vuex、脚手架中组件传值
    day 86 Vue学习之五DIY脚手架、webpack使用、vue-cli的使用、element-ui
  • 原文地址:https://www.cnblogs.com/imakf/p/13715160.html
Copyright © 2011-2022 走看看