• 模板汇总


    模板汇总

    也许是中学生涯最后一次打板子了呀...


    KMP模式匹配

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N = 1000005;
    char a[N], b[N];
    int a1, b1, Next[N];
    int main(){
    	cin >> a + 1;
    	cin >> b + 1;
    	a1 = strlen(a + 1);
    	b1 = strlen(b + 1);
    	Next[1] = 0;
    	for(int i = 2, j = 0; i <= b1; i++){
    		while( j > 0 && b[j + 1] != b[i] ) j = Next[j];
    		if( b[i] == b[j + 1] ) j++;
    		Next[i] = j;
    	}
    	for(int i = 1, j = 0; i <= a1; i++){
    		while( j > 0 && a[i] != b[j + 1]) j = Next[j];
    		if(a[i] == b[j + 1]) j++;
    		if(j == b1) {
    			cout << i - j + 1 <<"
    ";
    			j = Next[j];
    		}
    	}
    	for(int i = 1; i <= b1; i++) cout << Next[i] <<" ";
    	return 0;
    } 
    

    Trie字典树

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int Trie[N][27], end[p] = 1, tot = 1;
    void insert(char* str){
    	int len = strlen(str), p = 1;
    	for(int k = 0; k < len; k++){
    		int ch = str[k] - 'a';
    		if(trie[p][ch] == 0) trie[p][ch] = ++tot;
    		p = trie[p][ch];
    	}
    	end[p] = 1;
    }
    bool search(char* str){
    	int len = strlen(str), p = 1;
    	for(int k = 0; k < len; k++){
    		p = trie[p][str[k]];
    		if(p == 0) return 0;
    	}
    	return end[p];
    }
    

    ST表

    值得注意的是,log函数最好配强制类型转换(不然poj会编译错误),转换的时候要用括号把log全部括一下,初始化的时候k要加一。初始化的时候j从0开始我被坑了无数次了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    const int N = 100005;
    int a[N][30], n, m, k;
    int read(){
    	int x = 0, ch = getchar();
    	while(ch < '0' || ch > '9') ch = getchar();
    	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    	return x;
    }
    int main(){
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++) a[i][0] = read();
    	k = int(log(n) / log(2) + 1);
    	for(int i = 1; i <= k; i++)
    	    for(int j = 0; j <= n - (1 << i) + 1; j++)
    	        a[j][i] = max(a[j][i - 1], a[j + (1 << (i-1))][i - 1]);
    	while(m--){
    		int x = read(), y = read();
    		k = int(log(y - x + 1) / log(2));
    		cout << max(a[x][k], a[y - (1 << k) + 1][k]) << "
    ";
    	}
    	return 0;
    }
    
    

    单源最短路径 (dijkstra)

    注意打标记和判重都在取出队头的时候进行

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N = 500005;
    int ver[N], head[N], Next[N], edge[N], tot;
    int n, m, s;
    void add(int x, int y, int z){
    	ver[++tot] = y, edge[tot] = z;
    	Next[tot] = head[x], head[x] = tot; 
    }
    int read(){
    	int x = 0, ch = getchar();
    	while(ch < '0' || ch > '9') ch = getchar();
    	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    	return x;
    }
    
    /*Dijkstra*/
    int d[N], v[N];
    void dijkstra(int s){
    	memset(d, 0x3f, sizeof d);
    	memset(v, 0, sizeof v);
    	priority_queue< pair< int, int > > q;
    	q.push(make_pair(0, s)); d[s] = 0;
    	while(q.size()){
    		int x = q.top().second; q.pop();
    		if(v[x]) continue;
    		v[x] = 1;
    		for(int i = head[x]; i; i = Next[i]){
    			int y = ver[i], z = edge[i];
    			if(d[y] > d[x] + z){
    				d[y] = d[x] + z;
    				q.push(make_pair(-d[y], y));
    			}
    		}
    	}
    }
    int main(){
    	cin >> n >> m >> s;
    	for(int i = 1; i <= m; i++){
    		int x = read(), y = read(), z = read();
    		add(x, y, z);
    	}
    	dijkstra(s);
    	for(int i = 1; i <= n; i++){
    		if(d[i] == 0x3f3f3f3f)
    			cout << "2147483647 ";
    		else cout << d[i] <<" ";
    	}
    	return 0;
    }
    

    单源最短路径(SPFA)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N = 500005;
    int ver[N], head[N], Next[N], edge[N], tot;
    int n, m, s;
    void add(int x, int y, int z){
    	ver[++tot] = y, edge[tot] = z;
    	Next[tot] = head[x], head[x] = tot; 
    }
    int read(){
    	int x = 0, ch = getchar();
    	while(ch < '0' || ch > '9') ch = getchar();
    	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    	return x;
    }
    int d[N], v[N];
    /* spfa */
    void spfa(int s){
    	memset(d, 0x3f, sizeof d);
    	memset(v, 0, sizeof v);
    	queue<int> q;
    	q.push(s); v[s] = 1; d[s] = 0;
    	while(q.size()){
    		int x = q.front(); q.pop();
    		v[x] = 0;
    		for(int i = head[x]; i; i = Next[i]){
    			int y = ver[i], z = edge[i];
    			if(d[y] > d[x] + z){
    				d[y] = d[x] + z;
    				if(!v[x]) q.push(y), v[y] = 1;
    			}
    		}
    	}
    }
    int main(){
    	cin >> n >> m >> s;
    	for(int i = 1; i <= m; i++){
    		int x = read(), y = read(), z = read();
    		add(x, y, z);
    	}
    	spfa(s);
    	for(int i = 1; i <= n; i++){
    		if(d[i] == 0x3f3f3f3f)
    			cout << "2147483647 ";
    		else cout << d[i] <<" ";
    	}
    	return 0;
    }
    

    扩展欧几里得

    (x = frac{c}{d}x_0 + k frac{b}{d}, y = frac {c}{d}y_0 - k frac{a}{d})

    #include<iostream>
    #define ll long long 
    using namespace std;
    int exgcd1(int a, int b, int &x, int &y){
    	if(b == 0) {
    		x = 1, y = 0;
    		return a;
    	}
    	int d = exgcd1(b, a % b, x, y);
    	int z = x; x = y, y = z - (a / b) * y;
    	return d;
    }
    ll exgcd(ll a, ll b, ll &x, ll &y){
    	if(b == 0){
    		x = 1, y = 0;
    		return a;
    	} 
    	int d = exgcd(b, a % b, x, y);
    	int z = x; x = y, y = z - (a / b) * y;
    	return d;
    }
    int main(){
    	ll a, b, x, y, d;
    	cin >> a >> b;
    	d = exgcd(a, b, x, y);
    	cout << (x % (b / d) + (b / d)) % (b / d) <<"
    ";
    	return 0;
    }
    

    最近公共祖先 LCA

    • 树上倍增法
      敲这个板子出了一堆错误。所以要记得空间开到两倍,lca的大于等于号。
      错的太智障了
    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N = 1000005;
    int ver[N], head[N], Next[N], tot;
    int n, m, s, k, f[N][25], d[N];
    void add(int x, int y){
    	ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
    }
    void bfs(){
    	queue<int> q;
    	q.push(s); d[s] = 1; 
    	while(q.size()){
    		int x = q.front(); q.pop();
    		for(int i = head[x]; i; i = Next[i]){
    			int y = ver[i];
    			if(d[y]) continue;
    			d[y] = d[x] + 1;
    			f[y][0] = x;
    			for(int j = 1; j <= k; j++)
    				f[y][j] = f[f[y][j - 1]][j - 1];
    			q.push(y);
    		}
    	}
    }
    int lca(int x, int y){
    	if(d[y] < d[x]) swap(x, y);
    	for(int i = k; i >= 0; i--)
    		if(d[f[y][i]] >= d[x]) y = f[y][i];
    	if(x == y) return x;
    	for(int i = k; i >= 0; i--)
    	    if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    	return f[x][0];
    }
    
    int read(){
    	int x = 0, ch = getchar();
    	while(ch < '0' || ch > '9') ch = getchar();
    	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    	return x;
    }
    int main(){
    	cin >> n >> m >> s;
    	k = (int)( log(n) / log(2) ) + 1;
    	for(int i = 1; i < n; i++) {
    		int x = read(), y = read();
    		add(x, y), add(y, x);
    	}
    	bfs();
    	while(m--){
    		int x = read(), y = read();
    		cout << lca(x, y) <<"
    ";
    	}
    	
    	return 0;
    }
    

    • 树链剖分法
    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N = 1000005;
    int ver[N], head[N], Next[N], tot;
    int d[N], son[N], f[N], top[N], v[N], size[N];
    int n, m, s;
    void add(int x, int y){
    	ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
    }
    
    void dfs1(int x){
    	v[x] = 1;
    	size[x] = 1;
    	for(int i = head[x]; i; i = Next[i]){
    		int y = ver[i];
    		if(v[y]) continue;
    		d[y] = d[x] + 1;
    		dfs1(y);
    		f[y] = x;
    		size[x] += size[y];
    		if(!son[x] || size[y] > size[son[x]])
    			son[x] = y;
    	}
    }
    void dfs2(int x, int p){
    	top[x] = p;
    	if(son[x]) dfs2(son[x], p);
    	for(int i = head[x]; i; i = Next[i]){
    		int y = ver[i];
    		if(y == f[x] || y == son[x]) continue;
    		dfs2(y, y);
    	}
    }
    int lca(int x, int y){
    	while(top[x] != top[y]) 
    		if(d[top[x]] > d[top[y]]) x = f[top[x]];
    		else y = f[top[y]];
    	if(d[x] > d[y]) return y;
    	return x;
    } 
    int read(){
    	int x = 0, ch = getchar();
    	while(ch < '0' || ch > '9') ch = getchar();
    	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    	return x;
    }
    int main(){
    	cin >> n >> m >> s;
    	for(int i = 1; i < n; i++) {
    		int x = read(), y = read();
    		add(x, y), add(y, x);
    	}
    	d[s] = 1;
    	dfs1(s);
    	dfs2(s, s);
    	while(m--){
    		int x = read(), y = read();
    		cout << lca(x, y) <<"
    ";
    	}
    	return 0;
    }
    

    最小生成树 Kruskal

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 200005;
    int n, m, f[N], ans = 0;
    struct node{
    	int x, y, z;
    }edge[N];
    bool cmp(node a, node b){
    	return a.z < b.z;
    }
    int get(int x){
    	if(x == f[x]) return x;
    	return f[x] = get(f[x]);
    }
    int main(){
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++) f[i] = i;
    	for(int i = 1; i <= m; i++){
    		cin >> edge[i].x >> edge[i].y >> edge[i].z;
    	}
    	sort(edge + 1, edge + m + 1, cmp);
    	for(int i = 1; i <= m; i++){
    		int x = edge[i].x, y = edge[i].y;
    		x = get(x), y = get(y);
    		if(x == y) continue;
    		f[x] = y;
    		ans += edge[i].z;
    	}
    	cout << ans;
    	return 0;
    }
    

    树的直径

    void dp(int x){
    	v[x] = 1;
    	for(int i = head[x]; i; i = Next[i]){
    		int y = ver[i];
    		if(v[y]) continue;
    		dp(y);
    		ans = max(ans, d[x] + d[y] + edge[i]);
    		d[x] = max(d[x], d[y] + edge[i]);
    	}
    }
    

    树状数组

    OI生涯学的第一个数据结构!
    板子超好写,难在分析题目中能用前缀和、差分解决的地方。

    void update(int x, int y){
    	for(; x <= n; x += x & -x)
    		s[x] += y;
    }
    int getsum(int x){
    	int ans = 0;
    	for(; x; x -= x & -x)
    		ans += s[x];
    	return ans;
    }
    

    归并排序

    (mid - i + 1)背下来就好啦

    #include<iostream>
    using namespace std;
    int a[100005], b[100005], ans;
    void merge_sort(int l, int r){
    	if(l == r) return;
    	int mid = (l + r) >> 1;
    	merge_sort(l, mid);
    	merge_sort(mid + 1, r);
    	int i = l, j = mid + 1, k = l;
    	while(i <= mid || j <= r){
    		if(j > r || ( a[i] <= a[j] && i <= mid ))
    			b[k++] = a[i++];
    		else 
    		    b[k++] = a[j++], ans += mid - i + 1;
    	}
    	for(int i = l; i <= r; i++)
    		a[i] = b[i];
    }
    int main(){
    	int n;
    	cin >> n;
    	for(int i = 1; i <= n; i++) cin >> a[i];
    	merge_sort(1, n);
    	cout << ans;
    	return 0;
    }
    

    乘法逆元

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N = 3000005;
    long long a[N], n, p;
    int main(){
    	cin >> n >> p; 
    	a[0] = a[1] = 1;
    	cout << 1 <<"
    ";
    	for(int i = 2; i <= n; i++){
    		a[i] = (p - p / i) * a[p % i] % p;
    		cout << a[i] <<"
    ";
    	} 
    
    	return 0;
    }
    

    卢卡斯定理

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N = 1000005;
    long long a[N];
    long long n, m, p;
    
    long long fp(long long a, long long b){
    	long long ans = 1;
    	for(; b; b >>= 1){
    		if(b & 1) ans = ans * a % p;
    		a = a * a % p;
    	}
    	
    	return ans;
    }
    
    
    long long C(long long n, long long m){
    	if(n < m) return 0;
    	return (a[n] * fp(a[m], p - 2)) % p * fp(a[n - m], p - 2) % p ;
    }
    long long Lucas(long long n, long long m){
    	if(m == 0) return 1;
    	return C(n % p, m % p) * Lucas(n / p, m / p) % p;
    }
    
    int read(){
    	int x = 0, ch = getchar();
    	while(ch < '0' || ch > '9') ch = getchar();
    	while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    	return x;
    }
    
    
    
    int main(){
    //	for(int i = 2; i < p; i++) a[i] = (p - p / i) * a[p % i] % p;
    	
    	int t = read();
    	while(t--){
    		n = read(), m = read(), p = read();
    		a[0] = 1;
    		for(int i = 1; i <= p; i++) a[i] = a[i - 1] * i % p;
    		cout << Lucas(n + m, n) <<"
    ";
    	}
    	
    	
    	return 0;
    }
    

    线段树

    一个暑假的记忆,大概是我最有把握的模板了吧。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int SIZE = 100005;
    struct SegmentTree{
    	int l, r;
    	long long sum, add;
    }t[SIZE * 4];
    int a[SIZE];
    void build(int p, int l, int r){
    	t[p].l = l, t[p].r = r;
    	if(l == r) {
    		t[p].sum = a[l];
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	build(p*2, l, mid);
    	build(p*2+1, mid + 1, r);
    	t[p].sum = t[p*2].sum + t[p*2+1].sum;
    }
    void spread(int p){
    	if(t[p].add){
    		t[p*2].sum += (long long)(t[p*2].r - t[p*2].l + 1) * t[p].add;
    		t[p*2+1].sum += (long long)(t[p*2+1].r - t[p*2+1].l + 1) * t[p].add;
    		t[p*2].add += t[p].add;
    		t[p*2+1].add += t[p].add;
    		t[p].add = 0;
    	}
    }
    void change(int p, int l, int r, int val){
    	if(l <= t[p].l && r >= t[p].r){
    		t[p].add += val;
    		t[p].sum += (long long)(t[p].r - t[p].l + 1) * val;
    		return;
    	}
    	spread(p);
    	int mid = (t[p].l + t[p].r) >> 1;
    	if(l <= mid) change(p*2, l, r, val);
    	if(r > mid) change(p*2+1, l, r, val);
    	t[p].sum = t[p*2].sum + t[p*2+1].sum; 
    }
    long long ask(int p, int l, int r){
    	if(l <= t[p].l && r >= t[p].r) return t[p].sum;
    	spread(p);
    	int mid = (t[p].l + t[p].r) >> 1;
    	long long val = 0;
    	if(l <= mid) val += ask(p*2, l, r);
    	if(r > mid) val += ask(p*2+1, l, r);
    	return val;
    }
    int main(){
    	int n, m;
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++) cin >> a[i];
    	build(1, 1, n);
    	while(m--){
    		int f, x, y, h;
    		cin >> f >> x>> y;
    		if(f == 1){
    			cin >> h;
    			change(1, x, y, h);
    		}
    		if(f == 2){
    			cout << ask(1, x, y) <<"
    ";
    		}
    	}
    	return 0;
    }
    

    并查集

    板子不重要,路径压缩和带权才重要

    int get(int x){
    	if(x == fa[x]) return x;
    	return fa[x] = get(fa[x]);
    }
    void merge(int x, int y){
    	fa[get(x)] = get(y);
    }
    

    平衡树Treap

    #include<iostream>
    #include<cstdlib>
    using namespace std;
    const int SIZE = 100005;
    struct Treap{
    	int l, r;
    	int val, dat;
    	int size, cnt;
    }a[SIZE];
    int tot, root, n, INF=0x7fffffff;
    
    int New(int val){
    	a[++tot].val = val;
    	a[tot].dat = rand();
    	a[tot].size = a[tot].cnt = 1;
    	return tot;
    }
    
    void Update(int p){
    	a[p].size = a[a[p].l].size + a[a[p].r].size + a[p].cnt;
    }
    
    void Build(){
    	New(-INF), New(INF);
    	root = 1, a[1].r = 2;
    	Update(root);
    }
    
    void zig(int &p){
    	int q = a[p].l;
    	a[p].l = a[q].r, a[q].r = p, p = q;
    	Update(a[p].r), Update(p);
    }
    
    void zag(int &p){
    	int q = a[p].r;
    	a[p].r = a[q].l, a[q].l = p, p = q;
    	Update(a[p].l), Update(p); 
    }
    
    void Insert(int &p, int val){
    	if(p == 0){
    		p = New(val);
    		return;
    	}
    	if(a[p].val == val){
    		a[p].cnt++, Update(p);
    		return;
    	}
    	if(val < a[p].val){
    		Insert(a[p].l, val);
    		if(a[p].dat < a[a[p].l].dat) zig(p);
    	}
    	else{
    		Insert(a[p].r, val);
    		if(a[p].dat < a[a[p].r].dat) zag(p);
    	}
    	Update(p); 
    }
    
    int GetRankByVal(int p, int val){
    	if(p == 0) return 0;
    	if(val == a[p].val) return a[a[p].l].size;
    	if(val < a[p].val) return GetRankByVal(a[p].l, val);
    	return a[a[p].l].size + a[p].cnt + GetRankByVal(a[p].r, val);
    }
    
    int GetValByRank(int p, int rank){
    	if(p == 0) return INF;
    	if(a[a[p].l].size >= rank) return GetValByRank(a[p].l, rank);
    	if(a[a[p].l].size + a[p].cnt >= rank) return a[p].val;
    	return GetValByRank(a[p].r, rank - a[a[p].l].size - a[p].cnt);
    }
    
    int GetPrev(int val){
    	int ans = 1;
    	int p = root; 
    	while(p){
    		if(val == a[p].val){
    			if(a[p].l > 0){
    				p = a[p].l;
    				while(a[p].r > 0) p = a[p].r;
    				ans = p;
    			}
    			break;
    		}
    		if(a[ans].val < a[p].val && a[p].val < val) ans = p;
    		p = val < a[p].val ? a[p].l : a[p].r;
    	}
    	return a[ans].val;
    }
    int GetNext(int val){
    	int ans = 2;
    	int p = root;
    	while(p){
    		if(val == a[p].val){
    			if(a[p].r > 0){
    				p = a[p].r;
    				while(a[p].l > 0) p = a[p].l;
    				ans = p;
    			}
    			break;
    		}
    		if(a[ans].val > a[p].val && a[p].val > val) ans = p;
    		p = val < a[p].val ? a[p].l : a[p].r;
    	}
    	return a[ans].val;
    }
    
    void Remove(int &p, int val){
    	if(p == 0) return;
    	if(val == a[p].val){
    		if(a[p].cnt > 1){
    			a[p].cnt--, Update(p);
    			return;
    		}
    		if(a[p].l || a[p].r){
    			if(a[p].r == 0 && a[a[p].l].dat > a[a[p].r].dat)
    				zig(p), Remove(a[p].r, val);
    			else
    			    zag(p), Remove(a[p].l, val);
    			Update(p);
    		}else p = 0;
    		return;
    	}
    	val < a[p].val ? Remove(a[p].l, val) : Remove(a[p].r, val);
    	Update(p);
    }
    int main(){
    	Build();
    	cin >> n;
    	while(n--){
    		int opt, x;
    		cin >> opt >> x;
    		switch(opt){
    			case 1:
    				Insert(root, x);
    				break;
    			case 2:
    				Remove(root, x);
    				break;
    			case 3:
    				cout << GetRankByVal(root, x) - 1 <<"
    ";
    				break;
    			case 4:
    				cout << GetValByRank(root, x+1) <<"
    ";
    				break;
    			case 5:
    				cout << GetPrev(x) <<"
    ";
    				break;
    			case 6:
    				cout << GetNext(x) <<"
    ";
    				break;
    		}	
    	}
    	return 0;
    }
    

    平衡树Splay

    #include<iostream>
    using namespace std;
    
    const int _ = 100005;
    const int INF = 0x7fffffff;
    
    int n, opt, x;
    
    struct Spaly{
    	int root, tot, cnt[_], val[_], size[_], ch[_][2], fa[_];
    	
    	bool chk(int x){
    		return ch[fa[x]][1] == x;
    	}
    	
    	void pushup(int x){
    		if(!x) return;
    		size[x] = size[ch[x][0]] + size[ch[x][1]] + cnt[x]; 
    	}
    	
    	int newnode(int x){
    		val[++tot] = x;
    		cnt[tot] = size[tot] = 1;
    		ch[x][0] = ch[x][1] = 0;
    		return tot;
    	}
    	
    	void rotate(int x){
    		int y = fa[x], z = fa[y], k = chk(x), w = ch[x][k^1];
    		ch[y][k] = w, fa[w] = y;
    		ch[z][chk(y)] = x, fa[x] = z;
    		ch[x][k^1] = y, fa[y] = x;
    		pushup(y), pushup(x);
    	}
    	
    	void splay(int x, int goal = 0){
    		while(fa[x] != goal){
    			int y = fa[x], z = fa[y];
    			if(z != goal){
    				if(chk(x) == chk(y)) rotate(y);
    				else rotate(x);
    			}
    			rotate(x);
    		}
    		if(!goal) root = x;
    	}
    	
    	void insert(int x){
    		int cur = root, p = 0;
    		while(cur && x != val[cur]) 
    			p = cur, cur = ch[cur][x > val[cur]];
    		if(cur) ++cnt[cur], splay(cur);
    		else cur = ch[p][x > val[p]] = newnode(x), fa[cur] = p, splay(cur);
    	}
    	
    	void find(int x){
    		if(!root) return;
    		int cur = root;
    		while(ch[cur][x > val[cur]] && x != val[cur]) cur = ch[cur][x > val[cur]];
    		splay(cur);
    	}
    	
    	int rank(int x){
    		find(x);
    		return cnt[ch[root][0]] + 1;
    	}
    	
    	int kth(int k){
    		int cur = root;
    		while(1){
    			if(ch[cur][0] && k <= size[ch[cur][0]]) cur = ch[cur][0];
    			else if(k > size[ch[cur][0]] + cnt[cur]) k -= size[ch[cur][0]] + cnt[cur], cur = ch[cur][1];
    			else return cur;
    		}
    	}
    	
    	int pre(int x){
    		find(x);
    		if(val[root] < x) return root;
    		int cur = ch[root][0];
    		while(ch[cur][1]) cur = ch[cur][1];
    		return cur;
    	}
    	
    	int next(int x){
    		find(x);
    		if(val[root] > x) return root;
    		int cur = ch[root][1];
    		while(ch[cur][0]) cur = ch[cur][0];
    		return cur; 
    	}
    	
    	void remove(int x){
    		int u = pre(x), v = next(x);
    		splay(u), splay(v, u);
    		int w = ch[v][0];
    		if(cnt[w] > 1) --cnt[w], splay(w);
    		else size[0] = cnt[0] = ch[v][0] = 0;
    	}
    	
    	void maintain(int x){
    		if(!ch[x][0] && !ch[x][1]) size[x] = cnt[x];
    		if(ch[x][0]) maintain(ch[x][0]);
    		if(ch[x][1]) maintain(ch[x][1]);
    		pushup(x);
    	}
    	
    }T;
    
    int main(){
    	T.insert(-INF), T.insert(INF);
    	cin >> n;
    	for(int i=1; i<=n; i++){
    		cin >> opt >> x;
    		if(opt == 1) T.insert(x);
    		if(opt == 2) T.remove(x);
    		if(opt == 3) cout << T.rank(x) - 1 <<"
    ";
    		if(opt == 4) cout << T.val[T.kth(x)+1] <<"
    ";
    		if(opt == 5) cout << T.val[T.pre(x)] <<"
    ";
    		if(opt == 6) cout << T.val[T.next(x)] <<"
    ";
    	}	
    	
    	return 0;
    }
    
  • 相关阅读:
    个人作业2——英语学习APP案例分析
    结对编程1
    个人作业1——四则运算题目生成程序(基于控制台)
    个人附加作业
    个人作业3——个人总结(Alpha阶段)
    结对编程2--单元测试
    个人作业2——英语学习APP的案例分析
    结对编程1 李雯钰66、钱惠71
    个人作业1——四则运算题目生成程序(基于控制台)
    软件工程的实践项目课程的自我目标
  • 原文地址:https://www.cnblogs.com/hnoi/p/11869388.html
Copyright © 2020-2023  润新知