Codeforces 675D Tree Construction (splay)

2024-06-11 05:08

本文主要是介绍Codeforces 675D Tree Construction (splay),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自:https://blog.csdn.net/dreamon3/article/details/51436043

题意

往一个根为a[0]的二叉搜索树里面插数,每插一个数就输出他的父节点。

思路

根据二叉搜索树的性质,我们插进去一个数,他的父节点肯定是比他小的最大的和比他大的最小的数里面的两个,然后这两个节点找最深的那个就是他的父节点,我们可以给这些节点设置一个时间戳就能判断先后顺序了。 
在找那两个节点的时候我是直接用的splay找的,实际上我们可以直接用两个set一个储存负数一个储存正数然后两个lower_bound找到这两个数,因为比赛的时候比较捉急调了挺长时间再加上我对我的迭代器操作水平不怎么自信就直接splay找了= =

代码

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
typedef long long ll;
#define MD 1000000007
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
const int maxn = 100005;
int pre[maxn], key[maxn], ch[maxn][2], root, tot;
//父节点,键值,左右孩子0左1右,根节点,节点数量
int n;
void NewNode(int &r, int fa, int k)
{r = ++tot;pre[r] = fa;key[r] = k;ch[r][0] = ch[r][1] = 0;
}
void Rotate(int x, int kind)    //kind为1时右旋,为0左旋
{int y = pre[x];ch[y][!kind] = ch[x][kind];pre[ch[x][kind]] = y;if (pre[y])ch[pre[y]][ch[pre[y]][1]==y] = x;pre[x] = pre[y];ch[x][kind] = y;pre[y] = x;
}
void Splay(int r, int goal)
{while (pre[r] != goal){if (pre[pre[r]] == goal) Rotate(r, ch[pre[r]][0]==r); //左儿子右旋右儿子左旋else{int y = pre[r];int kind = (ch[pre[y]][0] == y); //y是左儿子时kind是1,y是右儿子时kind是1if (ch[y][kind] == r){Rotate(r, !kind);   //r和y左右不同时,之字形Rotate(r, kind);}else{Rotate(y, kind);   //r和y是一条线时,一字型Rotate(r, kind);}}}if (goal == 0) root = r;
}
int Insert(int k)
{int r = root;while (ch[r][key[r]<k]){//之前有过不再重复插入if (key[r] == k){Splay(r, 0);return 0;}r = ch[r][key[r]<k];}NewNode(ch[r][key[r]<k], r, k);Splay(ch[r][key[r]<k], 0);return 1;
}
int get_small(int x)
{int temp = ch[x][0];if (temp == 0) return INF;while (ch[temp][1])temp = ch[temp][1];return key[temp];
}
int get_big(int x)
{int temp = ch[x][1];if (temp == 0) return INF;while (ch[temp][0])temp = ch[temp][0];return key[temp];
}
map<int, int> mp;int main()
{//freopen("H:\\in.txt","r",stdin);//freopen("H:\\out.txt","w",stdout);while (scanf("%d", &n) != EOF){root = tot = 0;int ans = 0;for (int i = 1; i <= n; i++){int num;scanf("%d", &num);mp[num] = i;if (i == 1){NewNode(root, 0, num);continue;}if (Insert(num) == 0) continue;int a = get_small(root);int b = get_big(root);if (mp[a] > mp[b]) printf("%d ", a);else printf("%d ", b);}}return 0;
}

我的代码:

#include<bits/stdc++.h>
using namespace std;
#define dprintf if (debug) printf
#define rep(i, j, k) for (int i=j; i<k; i++)
const int N=100005, INF=0x7fffffff;
const int debug = 0;
int n, x;
struct Splay_Tree {struct Node {int key, son[2];} T[N];int fa[N], root, tot;void Rotate(int x, int kind) {int y=fa[x], z=fa[y];T[y].son[!kind]=T[x].son[kind], fa[T[x].son[kind]]=y;T[x].son[kind]=y, fa[y]=x;T[z].son[T[z].son[1]==y]=x, fa[x]=z;}void Splay(int x, int goal) {if(x==goal) return;while(fa[x]!=goal) {int y=fa[x], z=fa[y];int rx=T[y].son[0]==x, ry=T[z].son[0]==y;if(z==goal) Rotate(x, rx);else {if(rx==ry) Rotate(y, ry);else Rotate(x, rx);Rotate(x, ry);}}if(goal==0) root=x;}int Insert(int num){//dprintf("Insert %d\n", num);int rt = root;if (T[rt].key == num){Splay(rt, 0);return 0;}while (T[rt].son[T[rt].key<num]){//dprintf("rt = %d\n", T[rt].key);if (T[rt].key == num){Splay(rt, 0);return 0;}rt = T[rt].son[T[rt].key<num];}T[rt].son[T[rt].key<num] = ++tot;T[tot] = {num, 0, 0};fa[tot] = rt;//dprintf("before splay root = %d s0 = %d s1 = %d tot = %d\n", root, T[root].son[0], T[root].son[1], tot);Splay(tot, 0);//dprintf("after splay root = %d s0 = %d s1 = %d\n", root, T[root].son[0], T[root].son[1]);//dprintf("0 son0 = %d son1 = %d\n", T[0].son[0], T[0].son[1]);return 1;}int get_small(int rt){//dprintf("get_small rt = %d son0 = %d son1 = %d\n", T[rt].key, T[rt].son[0], T[rt].son[1]);int pos = T[rt].son[0];if (!pos) return INF;while (T[pos].son[1]) pos = T[pos].son[1];return T[pos].key;}int get_big(int rt){//dprintf("get_big rt = %d son0 = %d son1 = %d\n\n", T[rt].key, T[rt].son[0], T[rt].son[1]);   int pos = T[rt].son[1];if (!pos) return INF;while (T[pos].son[0])pos = T[pos].son[0];return T[pos].key;}void init() {root = 1; tot = 1;//dprintf("T[1].key = %d\n", T[1].key);}void de(int x){dprintf("No. %d key = %d lson.key = %d rson.key = %d\n", x, T[x].key, T[T[x].son[0]].key, T[T[x].son[1]].key);}
};Splay_Tree hehe;map<int, int> mp;
int main() {scanf("%d", &n);hehe.init();scanf("%d", &x);hehe.T[1] = {x, 0, 0};mp[x] = 0;mp[INF] = -1;rep(i, 1, n){scanf("%d", &x);mp[x] = i;if (hehe.Insert(x)){//hehe.de(hehe.root);            //hehe.de(0);int a = hehe.get_small(hehe.root);int b = hehe.get_big(hehe.root);//printf("a = %d b = %d\n mp[a] = %d mp[b] = %d\n ans = %d ", a, b, mp[a], mp[b], mp[a]>mp[b]? a:b);printf("%d ", mp[a]>mp[b]? a:b);}}return 0;
}

 

这篇关于Codeforces 675D Tree Construction (splay)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1050269

相关文章

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

Codeforces 482B 线段树

求是否存在这样的n个数; m次操作,每次操作就是三个数 l ,r,val          a[l] & a[l+1] &......&a[r] = val 就是区间l---r上的与的值为val 。 也就是意味着区间[L , R] 每个数要执行 | val 操作  最后判断  a[l] & a[l+1] &......&a[r] 是否= val import ja

树(Tree)——《啊哈!算法》

树 什么是树?树是一种特殊的图,不包含回路的连通无向树。 正因为树有着“不包含回路”这个特点,所以树就被赋予了很多特性。 一棵树中的任意两个结点有且仅有唯一的一条路径连通。一棵树如果有n个结点,那么它一定恰好有n-1条边。在一棵树中加一条边将会构成一个回路。 一棵树有且只有一个根结点。 没有父结点的结点称为根结点(祖先)。没有子结点的结点称为叶结点。如果一个结点既不是根结点也不是叶

226 Invert Binary Tree

//226 Invert Binary Tree//算法思路:主要使用递归算法public class Solution {public TreeNode invertTree(TreeNode root) {//1 出口 空节点if (root==null)return null;//2 递归 调用自己TreeNode left = root.left;TreeNode right = ro

Codeforces Round 971 (Div. 4) (A~G1)

A、B题太简单,不做解释 C 对于 x y 两个方向,每一个方向至少需要 x / k 向上取整的步数,取最大值。 由于 x 方向先移动,假如 x 方向需要的步数多于 y 方向的步数,那么最后 y 方向的那一步就不需要了,答案减 1 代码 #include <iostream>#include <algorithm>#include <vector>#include <string>

Codeforces#295(Div.2)A、B(模拟+BFS)

解题报告链接:点击打开链接 C. 题目链接:点击打开链接 解题思路: 对于给定的字符串,取出现次数最多的字母(可以同时有多个)。由这些字母组成长度为n的字符串,求有多少种组合。最后用数学知识即可。 完整代码: #include <algorithm>#include <iostream>#include <cstring>#include <climits>

Codeforces Round #281 (Div. 2)A(构造+暴力模拟)

题目链接:http://codeforces.com/problemset/problem/493/A 解题思路: 暴力的判断,分三种情况去判断即可。注意如果之前已经被罚下场后,那么在后面的罚下情况不应该算在输出结果内。 完整代码: #include <algorithm>#include <iostream>#include <cstring>#include <co