数据结构 1.0

扫描线

矩形面积并:

利用横线所截取的长度乘以纵向的差.   

这里特别注意一下线段树中最底层表示的是一个点,但长度中需要维护线段.  

所以不妨让线段树中的 $\mathrm{[l,r]}$ 区间实际维护 $\mathrm{[l, r+1)}$ 这条线段.                       

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N  200009 
#define ll long long 
#define pb push_back 
#define ls now << 1 
#define rs now << 1 | 1   
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;
struct Line {
	int x1, x2, y, d;  
	Line(int x1 = 0, int x2 = 0, int y = 0, int d = 0):x1(x1), x2(x2), y(y), d(d) {}  
}a[N];
int n , cnt , len[N << 2], A[N << 2], tot ; 
struct data {
	int sum, tag, l, r; 
	data() { sum = tag = l = r = 0; } 
}s[N << 2];  
void build(int l, int r, int now) {
	s[now].l = l, s[now].r = r;   
	if(l == r) return ; 
	int mid = (l + r) >> 1; 
	build(l, mid, ls), build(mid + 1, r, rs); 
}
void pushup(int now) {
	if(s[now].tag) 
		len[now] = A[s[now].r + 1] - A[s[now].l];    
	else {
		if(s[now].l != s[now].r) 
			len[now] = len[ls] + len[rs];  
		else len[now] = 0; 
	}
}    
void update(int l, int r, int now, int L, int R, int v) {
	if(l >= L && r <= R) {
		s[now].tag += v;  
		pushup(now); 
		return ; 
	}
	int mid = (l + r) >> 1;  
	if(L <= mid)  update(l, mid, ls, L, R, v); 
	if(R > mid)   update(mid + 1, r, rs, L, R, v); 
	pushup(now); 
}
bool cmp(Line i, Line j) { return i.y < j.y; } 
int main() {
	// setIO("input"); 
	scanf("%d", &n); 
	for(int i = 1; i <= n ; ++ i) {
		int x[2], y[2]; 
		scanf("%d%d%d%d", &x[0], &y[0], &x[1], &y[1]);   
		a[++ cnt] = Line(x[0], x[1], y[0], 1);  
		a[++ cnt] = Line(x[0], x[1], y[1], -1);    
		// 离散化横坐标即可.  
		A[++ tot] = x[0], A[++ tot] = x[1];  
	}
	sort(A + 1, A + 1 + tot); 
	tot = unique(A + 1, A + 1 + tot) - A - 1;    
	for(int i = 1; i <= cnt ; ++ i) {
		a[i].x1 = lower_bound(A + 1, A + 1 + tot, a[i].x1) - A; 
		a[i].x2 = lower_bound(A + 1, A + 1 + tot, a[i].x2) - A;   
	}   
	sort(a + 1, a + 1 + cnt, cmp);       
	// int pre = a[1].y;  
	build(1, tot , 1);  
	ll ans = 0; 
	for(int i = 1; i <= cnt ; ++ i) {        
		update(1, tot, 1, a[i].x1, a[i].x2 - 1, a[i].d);     
		ans += 1ll * len[1] * (a[i + 1].y - a[i].y);      
	}
	printf("%lld", ans); 
	return 0; 
}

  

平衡树

splay:   

对于 $\mathrm{p}$ 节点进行操作后应将 $\mathrm{p}$ 旋转至根节点以保证时间复杂度.  

但是旋转次数过多会导致效率降低,这里选择每 $10$ 次 $\mathrm{splay}$ 一次.  

#include <bits/stdc++.h>  
#define setIO(s) freopen(s".in","r", stdin) 
using namespace std;
int times;   
int judge() {
	++ times;  
	return times % 10 == 0; 
}
struct BST {
	#define N  400009  
	#define ls s[x].ch[0] 	
	#define rs s[x].ch[1] 
	#define inf 1000000000
	struct data {
		int f, v, size, ch[2];
		void clr() {
			f = v = size = ch[0] = ch[1] = 0; 
		} 
	}s[N]; 
	int tot, sta[N], top, root; 
	int newnode() {
		if(top) return sta[top -- ];   
		else return ++ tot;  
	}
	void era(int x) {
		sta[++ top] = x; 
	}
	void pushup(int x) {
		s[x].size = s[ls].size + s[rs].size + 1; 
	}
	int get(int x) { return s[s[x].f].ch[1] == x; }  
	void rotate(int x) {
		int old = s[x].f, fold = s[old].f, which = get(x);
		if(fold) 
			s[fold].ch[s[fold].ch[1] == old] = x; 
		s[old].ch[which] = s[x].ch[which ^ 1];  
		if(s[old].ch[which]) 
			s[s[old].ch[which]].f = old; 
		s[x].ch[which ^ 1] = old, s[old].f = x, s[x].f = fold; 
		pushup(old), pushup(x); 
	} 
	void splay(int x, int &tar) {   
		int o = s[tar].f;    
		// x 无论如何都会向上走一步.  
		for(int fa; (fa = s[x].f) != o; rotate(x)) 
			if(s[fa].f != o) 
				rotate(get(fa) == get(x) ? fa : x);  
		tar = x;  
	}  
	// 加入两个空哨. 
	void init() {
		int p = newnode(), q = newnode(); 
		s[p].v = -inf, s[p].f = q, s[p].size = 1;   
		s[q].v = inf, s[q].ch[0] = p, s[q].size = 2;    
		root = q;  
	}
	int ins(int &x, int fa, int v) {
		if(!x) {
			x = newnode(); 
			s[x].v = v, s[x].size = 1, s[x].f = fa;  
			return x;        
		}
		int p = ins(s[x].ch[v > s[x].v], x, v);   
		pushup(x); 
		return p ; 
	}
	void Ins(int v) {
		int p = ins(root, 0, v);    
		if(judge()) 
			splay(p, root);   
	}
	int get_pre(int x) {
		int q = s[x].ch[0]; 
		while(s[q].ch[1]) q = s[q].ch[1];  
		return q;
	}
	int get_aft(int x) {
		int q = s[x].ch[1]; 
		while(s[q].ch[0]) q = s[q].ch[0]; 
		return q; 
	}
	// 寻找最后一个小于等于 v 的.      
	int find(int x, int v) {        
		if(x == 0) return -1;    
		if(s[x].v > v) 
			return find(s[x].ch[0], v); 
		else {
			int q = find(s[x].ch[1], v);  
			return q == -1 ? x : q;  
		}   
	}
	void Del(int x) {      
		int p = find(root, x);   
		// 找到 p 了.  
		splay(p, root);   
		int pl = get_pre(p), pr = s[p].ch[1];   
		splay(pl, s[p].ch[0]);         
		s[pl].f = 0, s[pr].f = pl, s[pl].ch[1] = pr, pushup(pl); 
		root = pl;   
		s[p].clr(), era(p);    
	}
	int get_num(int x, int kth) {
		if(s[ls].size + 1 == kth)     
			return x;       
		if(kth <= s[ls].size) 
			return get_num(ls, kth); 
		else 
			return get_num(rs, kth - s[ls].size - 1);  
	}
	int get_rank(int x) {
		int p = find(root, x - 1);   
		splay(p, root);       
		return s[s[p].ch[0]].size + 1;   
	}      
	int query_num(int kth) {
		int p = get_num(root, kth + 1);   
		if(judge()) 
			splay(p, root); 
		return s[p].v;  
	}    
	int query_pre(int x) {
		int p = find(root, x - 1);      
		if(judge()) 
			splay(p, root); 
		return s[p].v;     
	}
	int query_aft(int x) {
		int p = find(root, x);   
		splay(p, root);  
		int q = get_aft(p); 
		splay(q, root);    
		return s[q].v;   
	} 
	#undef N            
	#undef ls 
	#undef rs 
	#undef inf 
}T; 
int main() {
	int pp = clock(); 
	// setIO("lim");  
	// freopen("input.out","w",stdout); 
	int Q; 
	scanf("%d", &Q); 
	T.init(); 
	for(int i = 1; i <= Q; ++ i) {
		int op, x, y, z;  
		scanf("%d%d", &op, &x); 
		if(op == 1) T.Ins(x); 
		if(op == 2) T.Del(x); 
		if(op == 3) printf("%d\n", T.get_rank(x)); 
		if(op == 4) printf("%d\n", T.query_num(x));  
		if(op == 5) printf("%d\n", T.query_pre(x)); 
		if(op == 6) printf("%d\n", T.query_aft(x));  
	}
	// printf("%d\n", clock() - pp) ; 
	return 0; 
}

  

posted @ 2022-01-14 23:51  guangheli  阅读(39)  评论(0)    收藏  举报