zoukankan      html  css  js  c++  java
  • LOJ#2018. 「AHOI / HNOI2017」单旋(平衡树模拟+set+线段树)

    https://loj.ac/problem/2018

    题解:

    • 先考虑只有加点怎么做?设要加的点是第(x)大,(x-1)的右儿子和(x+1)的左儿子一定恰好有一个是空的,加到那里即可。

    • 再模拟一下把最小值(x)给splay到根的过程,发现(x)到根的链几乎没有变,变得是:把(x)的右儿子接到(x)的父亲,把原来的根改为(x)的右儿子。

    • 再考虑深度的变化,发现除了(x)的右儿子那棵子树和(x)自己,其它点的深度都+1,我们很容易得到(x)的右儿子的值域区间是((a[x],a[fa[x]])),线段树区间加即可。

    • 还需要用一个set来加速找一个点的前驱和后继。

    • LL说splay中间的点也是可以做的,但是需要写lct。

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int N = 1e5 + 5;
    
    int m, op, n, x;
    
    #define i0 t[i].l
    #define i1 t[i].r
    struct nod {
    	struct tree {
    		int l, r;
    		ll x, c, lz; 
    	} t[N * 100];
    	
    	int rt, tt;
    	
    	void jia(int i, ll v) {
    		if(i) {
    			t[i].x += t[i].c * v;
    			t[i].lz += v;
    		}
    	}
    	void down(int i) {
    		if(t[i].lz) jia(i0, t[i].lz), jia(i1, t[i].lz), t[i].lz = 0;
    	}
    	void upd(int i) {
    		t[i].c = t[i0].c + t[i1].c;
    		t[i].x = t[i0].x + t[i1].x;
    	}
    	
    	int pl, pr; ll px;
    	
    	void dg(int i, int x, int y) {
    		if(y < pl || x > pr) return;
    		if(x == y) { px = t[i].x; return;}
    		int m = x + y >> 1; down(i);
    		dg(i0, x, m); dg(i1, m + 1, y);
    	}
    	
    	int dep(int x) {
    		pl = pr = x;
    		dg(rt, 1, 1e9);
    		return px;
    	}
    	
    	void dd(int &i, int x, int y) {
    		if(y < pl || x > pr) return;
    		if(!i) i = ++ tt;
    		if(x == y) {
    			t[i].c = 1; t[i].x = px;
    			return;
    		}
    		int m = x + y >> 1; down(i);
    		dd(i0, x, m); dd(i1, m + 1, y);
    		upd(i);
    	}
    	
    	void cdep(int x, int y) {
    		pl = pr = x, px = y;
    		dd(rt, 1, 1e9);
    	}
    	
    	void du(int i, int x, int y) {
    		if(y < pl || x > pr || !i) return;
    		if(x >= pl && y <= pr) {
    			jia(i, px); return;
    		}
    		int m = x + y >> 1; down(i);
    		du(i0, x, m); du(i1, m + 1, y);
    		upd(i);
    	}
    	
    	void add(int x, int y, int z) {
    		pl = x, pr = y, px = z;
    		du(rt, 1, 1e9);
    	}
    		
    	void dt(int &i, int x, int y) {
    		if(y < pl || x > pr) return;
    		if(x == y) {
    			i = 0;
    			return;
    		}
    		int m = x + y >> 1; down(i);
    		dt(i0, x, m); dt(i1, m + 1, y);
    		upd(i);
    	}
    	
    	void cl(int x) {
    		pl = pr = x;
    		dt(rt, 1, 1e9);
    	}
    } tr;
    
    multiset<int> s;
    map<int, int> id;
    int a[N], t[N][2], fa[N];
    
    int rt;
    
    int add(int x) {
    	a[++ n] = x; id[x] = n;
    	if(s.empty()) {
    		s.insert(x);
    		tr.cdep(x, 1);
    		rt = n;
    		return 1;
    	}
    	int p = 0, q = 0;
    	if((*--s.end()) > x) p = id[*s.upper_bound(x)];
    	if((*s.begin()) < x) q = id[*--s.upper_bound(x)];
    	int D;
    	if(!q || (p && !t[p][0])) {
    		fa[n] = p;
    		t[p][0] = n;
    		D = tr.dep(a[p]);
    	} else {
    		fa[n] = q;
    		t[q][1] = n;
    		D = tr.dep(a[q]);
    	}
    	D ++;
    	tr.cdep(x, D);
    	s.insert(x);
    	return D;
    }
    
    int ro(int k) {
    	int x = k ? id[(*s.begin())] : id[(*--s.end())];
    	if(x == rt) return 1;
    	int ans = tr.dep(a[x]);
    	tr.add(1, 1e9, 1);
    	if(t[x][k]) {
    		if(k) {
    			tr.add(a[x] + 1, a[fa[x]] - 1, -1);
    		} else {
    			tr.add(a[fa[x]] + 1, a[x] - 1, -1);
    		}
    	}
    	tr.cdep(a[x], 1);
    	fa[t[x][k]] = fa[x]; t[fa[x]][!k] = t[x][k];
    	fa[rt] = x; t[x][k] = rt; fa[x] = 0;
    	rt = x;
    	return ans;
    }
    
    void cl(int k) {
    	int x = k ? id[(*s.begin())] : id[(*--s.end())];
    	s.erase(s.find(a[x]));
    	tr.add(1, 1e9, -1);
    	tr.cl(a[x]);
    	rt = t[x][k]; fa[rt] = 0;
    }
    
    int main() {
    	scanf("%d", &m);
    	fo(ii, 1, m) {
    		scanf("%d", &op);
    		if(op == 1) {
    			scanf("%d", &x);
    			pp("%d
    ", add(x));
    		} else
    		if(op == 2) {
    			pp("%d
    ", ro(1));
    		} else
    		if(op == 3) {
    			pp("%d
    ", ro(0));
    		} else
    		if(op == 4) {
    			pp("%d
    ", ro(1));
    			cl(1);
    		} else {
    			pp("%d
    ", ro(0));
    			cl(0);
    		}
    	}
    }
    
  • 相关阅读:
    MDA模型定义及扩展
    java中 i = i++和 j = i++ 的区别
    nginx+tomcat负载均衡和session复制
    HDU 4010.Query on The Trees 解题报告
    codeforces 165D.Beard Graph 解题报告
    zoj 3209.Treasure Map(DLX精确覆盖)
    hdu 1155 Bungee Jumping
    选择Nginx的理由
    九九乘法表
    K
  • 原文地址:https://www.cnblogs.com/coldchair/p/13064798.html
Copyright © 2011-2022 走看看