1067 Sort with Swap(0,*) 麻烦
题目很简单,给一个 [0, N)乱序的序列,n <= 10 ^ 5,只能用 0 和其它元素交换,问要交换多少次才能恢复升序。
想了想没有想到计算的办法,那就模拟吧。刚开始只存了这个序列,需要找元素的时候就得顺序查找,果然超时了。
改,又用了一个反向索引,记录每一个元素目前的位置。结果还有 case 超时。
后来终于不超时了。我放弃了之前“寻找还有没有不在其位的元素”的时候顺序查找的办法,而是用一个值记录还有多少个元素乱序。这里又折腾了半天,因为没想通,一般交换一次是有一个元素归位,但是当交换一个环,0恰好也归位时会多有一个元素归位;一个环结束后还得把 0 拿出来以启动下一次交换,这个操作会把本身在位置的 0 拉出来,乱序元素会增加 1。当乱序元素数为 0,就可以结束循环了。
不过把 0 拉出来跟任意一个乱序元素交换的时候,又涉及到顺序查找哪个元素是乱的。这里又用了一个数 wrong0 记录第一个乱序的元素,它每次都继续往后走,就不用从头循环了。
总之,当我去除了所有存在的顺序查找/遍历操作,就不超时了:-) 真是有毒的题。
丑唧唧的代码:
# include <cstdio>
# include <cstdlib>
int seq[100100];
int N;
int ans = 0;
int idx[100100]; //反向查找
int nWrong = 0;
int wrong0 = 1;
void swap(int n) { //0与n交换
//printf("swap 0 and %3d: ", n);
int idx0 = idx[0];
seq[idx[n]] = 0; idx[0] = idx[n];
seq[idx0] = n; idx[n] = idx0;
ans++;
}
int main() {
scanf("%d", &N);
for (int i = 0; i < N; i++) {
scanf("%d", seq + i);
idx[seq[i]] = i;
if (seq[i] != i) {
nWrong++;
}
}
int temp;
while (nWrong > 0) {
if (idx[0] == 0) {
//找一个交换
for (; wrong0 < N; wrong0++) {
if (idx[wrong0] != wrong0) {
swap(seq[wrong0]);
nWrong ++;
break;
}
}
}
else {
swap(idx[0]);
nWrong--;
if (idx[0] == 0) nWrong--;
}
/*for (int i = 0; i < N; i++) {
printf("%d ", seq[i]);
}printf("\n");
for (int i = 0; i < N; i++) {
printf("%d ", idx[i]);
}printf("\n");
printf("nWrong = %d\n", nWrong);*/
}
printf("%d", ans);
return 0;
}
1066 Root of AVL Tree AVL树!
简单粗暴考你 AVL 树:给一个插入的序列,求最后树根是几。我佛佛佛。。。算了,认真写吧。在两眼一抹黑,也找不到之前写过的 AVL 树的情况下,凭着我奇葩的想象力,楞是从题目配图里找到了 AVL 树的规律。经过长时间的 debug (主要是处理不好 NULL 和 root 节点,到处报错)之后竟然通过了。。。通过了。。。
# include <cstdio>
#define max(a,b) ((a)>(b)? (a):(b))
struct node {
int data;
node *p, *lc, *rc;
};
node *root = NULL;
int N;
int hgt(node* pos) { //节点的高度,空树的高度为-1,单个节点的高度为0,有一个孩子的节点高度为1
if (pos == NULL) return -1;
return max(hgt(pos->lc), hgt(pos->rc)) + 1;
}
int balFac(node *pos) { //左孩子高度-右孩子高度
int lh, rh;
if (pos->lc == NULL) lh = -1; else lh = hgt(pos->lc);
if (pos->rc == NULL) rh = -1; else rh = hgt(pos->rc);
return lh - rh;
}
void insertAsRoot(int n) { //插入 root
root = new node;
root->data = n;
root->lc = NULL;
root->rc = NULL;
root->p = NULL;
}
node *insertAsLc(node *pos, int n) { //插入到pos的左孩子
node *newnode = new node;
newnode->data = n;
newnode->lc = NULL;
newnode->rc = NULL;
newnode->p = pos;
pos->lc = newnode;
return newnode;
}
node *insertAsRc(node *pos, int n) { //插入到pos的右孩子
node *newnode = new node;
newnode->data = n;
newnode->lc = NULL;
newnode->rc = NULL;
newnode->p = pos;
pos->rc = newnode;
return newnode;
}
void leftRotate(node *pos) {
node *b = pos->rc, *c = pos->rc->rc, *d = pos->rc->lc, *e = pos->lc;
if (pos->p) {
if (pos->p->lc == pos) { //是左孩子
pos->p->lc = b;
}
else if (pos->p->rc == pos) { //是右孩子
pos->p->rc = b;
}
}
else {
root = b;
}
b->p = pos->p;
pos->rc = d; if (d) d->p = pos;
b->lc = pos; pos->p = b;
}
void rightRotate(node *pos) {
node *b = pos->lc, *c = pos->lc->lc, *d = pos->lc->rc, *e = pos->rc;
if (pos->p) {
if (pos->p->lc == pos) { //是左孩子
pos->p->lc = b;
}
else if (pos->p->rc == pos) { //是右孩子
pos->p->rc = b;
}
}
else { //转的是root
root = b;
}
b->p = pos->p;
pos->lc = d; if(d) d->p = pos;
pos->p = b; b->rc = pos;
}
void insert(int n) {
if (root == NULL) { //空的
insertAsRoot(n);
}
else { //树非空
node *x = root, *prev = NULL;
while (x) {
if (n < x->data) {
prev = x; x = x->lc;
}
else {
prev = x; x = x->rc;
}
}
if (n < prev->data) x = insertAsLc(prev, n); else x = insertAsRc(prev, n); //插入节点
x = x->p->p; //爷爷可能开始不平衡
while (x) { //找最先失衡的祖先
if (balFac(x) >= 2 || balFac(x) <= -2) {
if (balFac(x) == -2 && balFac(x->rc) == -1) {
leftRotate(x);
}
else if (balFac(x) == 2 && balFac(x->lc) == 1) {
rightRotate(x);
}
else if (balFac(x) == -2 && balFac(x->rc) == 1) {
rightRotate(x->rc);
leftRotate(x);
}
else if(balFac(x) == 2 && balFac(x->lc) == -1) {
leftRotate(x->lc);
rightRotate(x);
}
break;
}
x = x->p;
}
}
}
int main() {
scanf("%d", &N);
int t;
for (int i = 0; i < N; i++) {
scanf("%d", &t);
insert(t);
}
printf("%d", root->data);
return 0;
}
送自己一朵小 Fa Fa~