#include <stdio.h>
#include <stdlib.h>
#define RED 1
#define BLACK 2
struct node {
long long key;
struct node *left, *right, *p;
long long color;
long long size;
};
typedef struct node *NODEPTR;
struct node NIL;
NODEPTR NILPTR = &NIL;
void inorder(NODEPTR x) {
if (x != NILPTR) {
inorder(x->left);
printf("(%lld,%lld) ", x
->key
, x
->size
); inorder(x->right);
}
//putchar('\n');
}
void preorder(NODEPTR x) {
if (x != NILPTR) {
preorder(x->left);
preorder(x->right);
}
//putchar('\n');
}
NODEPTR search(NODEPTR root, long long k) {
if (root == NILPTR || root->key == k)
return root;
if (k < root->key)
return search(root->left, k);
else
return search(root->right, k);
}
NODEPTR minimum(NODEPTR root) {
while (root->left != NILPTR)
root = root->left;
return root;
}
NODEPTR maximum(NODEPTR root) {
while (root->right != NILPTR)
root = root->right;
return root;
}
NODEPTR successor(NODEPTR root, long long x) {
NODEPTR temp = search(root, x);
if (temp == NILPTR) {
printf("%lld not in tree\n", x
); return temp;
}
if (temp->right != NILPTR)
return minimum(temp->right);
NODEPTR y = temp->p;
while (y != NILPTR && temp == y->right) {
temp = y;
y = y->p;
}
return y;
}
NODEPTR predecessor(NODEPTR root, long long x) {
NODEPTR temp = search(root, x);
if (temp == NILPTR) {
printf("%lld not in tree\n", x
); return temp;
}
if (temp->left != NILPTR)
return maximum(temp->left);
NODEPTR y = temp->p;
while (y != NILPTR && temp == y->left) {
temp = y;
y = y->p;
}
return y;
}
void leftrotate(NODEPTR *treeroot, NODEPTR x) {
NODEPTR y = x->right;
x->right = y->left;
if (y->left != NILPTR)
y->left->p = x;
y->p = x->p;
if (x->p == NILPTR)
*treeroot = y;
else if (x->p->left == x)
x->p->left = y;
else
x->p->right = y;
y->left = x;
x->p = y;
y->size = x->size;
x->size = x->left->size + x->right->size +1;
}
void rightrotate(NODEPTR *treeroot, NODEPTR y) {
NODEPTR x = y->left;
y->left = x->right;
if (x->right != NILPTR)
x->right->p = y;
x->p = y->p;
if (y->p == NILPTR)
*treeroot = x;
else if (y->p->left == y)
y->p->left = x;
else
y->p->right = x;
x->right = y;
y->p = x;
x->size = y->size;
y->size = y->left->size + y->right->size + 1;
}
void rbinsertfixup(NODEPTR *treeroot, NODEPTR z) {
while (z->p->color == RED) {
if (z->p == z->p->p->left) {
NODEPTR y = z->p->p->right;
if (y->color == RED) {
z->p->color = BLACK;
y->color = BLACK;
z->p->p->color = RED;
z = z->p->p;
}
else {
if (z == z->p->right) {
z = z->p;
leftrotate(treeroot,z);
}
z->p->color = BLACK;
z->p->p->color = RED;
rightrotate(treeroot,z->p->p);
}
}
else {
NODEPTR y = z->p->p->left;
if (y->color == RED) {
z->p->color = BLACK;
y->color = BLACK;
z->p->p->color = RED;
z = z->p->p;
}
else {
if (z == z->p->left) {
z = z->p;
rightrotate(treeroot,z);
}
z->p->color = BLACK;
z->p->p->color = RED;
leftrotate(treeroot,z->p->p);
}
}
}
(*treeroot)->color = BLACK;
}
void rbinsert(NODEPTR *treeroot, long long z) {
NODEPTR Z
= (NODEPTR
) malloc(sizeof(struct node
)); Z->key = z;
NODEPTR y = NILPTR;
NODEPTR x = *treeroot;
while (x != NILPTR) {
y = x;
y->size++;
if (Z->key < x->key)
x = x->left;
else if (Z->key > x->key)
x = x->right;
else {
NODEPTR temp = x;
while (x != NILPTR) {
x->size--;
x = x->p;
}
return;
}
}
Z->p = y;
if (y == NILPTR)
*treeroot = Z;
else if (Z->key < y->key)
y->left = Z;
else
y->right = Z;
Z->left = NILPTR;
Z->right = NILPTR;
Z->color = RED;
Z->size = 1;
rbinsertfixup(treeroot,Z);
}
void rbtransplant(NODEPTR *treeroot, NODEPTR u, NODEPTR v) {
if (u->p == NILPTR)
*treeroot = v;
else if (u == u->p->left)
u->p->left = v;
else
u->p->right = v;
v->p = u->p;
}
void rbdeletefixup(NODEPTR *treeroot, NODEPTR x) {
while (x != *treeroot && x->color == BLACK) {
if (x == x->p->left) {
NODEPTR w = x->p->right;
if (w->color == RED) {
w->color = BLACK;
x->p->color = RED;
leftrotate(treeroot,x->p);
w = x->p->right;
}
if (w->left->color == BLACK && w->right->color == BLACK) {
w->color = RED;
x = x->p;
}
else {
if (w->right->color == BLACK) {
w->left->color = BLACK;
w->color = RED;
rightrotate(treeroot,w);
w = x->p->right;
}
w->color = x->p->color;
x->p->color = BLACK;
w->right->color = BLACK;
leftrotate(treeroot,x->p);
x = *treeroot;
}
}
else {
NODEPTR w = x->p->left;
if (w->color == RED) {
w->color = BLACK;
x->p->color = RED;
rightrotate(treeroot,x->p);
w = x->p->left;
}
if (w->left->color == BLACK && w->right->color == BLACK) {
w->color = RED;
x = x->p;
}
else {
if (w->left->color == BLACK) {
w->right->color = BLACK;
w->color = RED;
leftrotate(treeroot,w);
w = x->p->left;
}
w->color = x->p->color;
x->p->color = BLACK;
w->left->color = BLACK;
rightrotate(treeroot,x->p);
x = *treeroot;
}
}
}
x->color = BLACK;
}
void rbdelete(NODEPTR *treeroot, long long z) {
NODEPTR Z = search(*treeroot, z);
if (Z == NILPTR) {
//prlong longf("Node to be deleted not found\n");
return;
}
NODEPTR tmp = Z->p;
while (tmp != NILPTR) {
tmp->size--;
tmp = tmp->p;
}
NODEPTR y = Z;
long long yoc = y->color;
NODEPTR x;
if (Z->left == NILPTR) {
x = Z->right;
rbtransplant(treeroot,Z,Z->right);
}
else if (Z->right == NILPTR) {
x = Z->left;
rbtransplant(treeroot,Z,Z->left);
}
else {
y = minimum(Z->right);
yoc = y->color;
x = y->right;
if (y->p == Z)
x->p = y;
else {
rbtransplant(treeroot,y,y->right);
y->right = Z->right;
y->right->p = y;
}
rbtransplant(treeroot,Z,y);
y->left = Z->left;
y->left->p = y;
y->color = Z->color;
}
if (yoc == BLACK)
rbdeletefixup(treeroot,x);
}
NODEPTR kth(NODEPTR treeroot, long long K) {
long long currrank = treeroot->left->size + 1;
NODEPTR y = treeroot;
while (y != NILPTR && currrank != K) {
if (K < currrank)
y = y->left;
else {
K = K - currrank;
y = y->right;
}
if (y == NILPTR)
return NILPTR;
currrank = y->left->size + 1;
}
return y;
}
long long cnt(NODEPTR treeroot, long long x) {
long long ans = 0;
NODEPTR y = treeroot;
while (y != NILPTR) {
if (y->key > x)
y = y->left;
else if (y->key < x) {
ans += y->left->size + 1;
y = y->right;
}
else
return ans + y->left->size;
}
return ans;
}
main()
{
NIL.left = NIL.right = NIL.p = NILPTR;
NIL.color = BLACK;
NODEPTR tree = NILPTR;
long long Q;
long long x, k;
NODEPTR temp;
char c[2];
while (Q--) {
switch (c[0]) {
case 'I':
rbinsert(&tree, x);
break;
case 'D':
rbdelete(&tree, x);
break;
case 'K':
temp = kth(tree, k);
if (temp != NILPTR)
else
break;
case 'C':
printf("%lld\n", cnt
(tree
,x
)); break;
default:
break;
}
}
/*inorder(tree);
putchar('\n');
preorder(tree);
putchar('\n');*/
return 0;
}
I2luY2x1ZGUgPHN0ZGlvLmg+CiNpbmNsdWRlIDxzdGRsaWIuaD4KCiNkZWZpbmUgUkVEICAgIAkxCiNkZWZpbmUgQkxBQ0sJMgoKc3RydWN0IG5vZGUgewoJbG9uZyBsb25nIGtleTsKCXN0cnVjdCBub2RlICpsZWZ0LCAqcmlnaHQsICpwOwoJbG9uZyBsb25nIGNvbG9yOwoJbG9uZyBsb25nIHNpemU7Cn07Cgp0eXBlZGVmIHN0cnVjdCBub2RlICpOT0RFUFRSOwpzdHJ1Y3Qgbm9kZSBOSUw7Ck5PREVQVFIgTklMUFRSID0gJk5JTDsKCnZvaWQgaW5vcmRlcihOT0RFUFRSIHgpIHsKCWlmICh4ICE9IE5JTFBUUikgewoJCWlub3JkZXIoeC0+bGVmdCk7CgkJcHJpbnRmKCIoJWxsZCwlbGxkKSAiLCB4LT5rZXksIHgtPnNpemUpOwoJCWlub3JkZXIoeC0+cmlnaHQpOwoJfQoJLy9wdXRjaGFyKCdcbicpOwp9Cgp2b2lkIHByZW9yZGVyKE5PREVQVFIgeCkgewoJaWYgKHggIT0gTklMUFRSKSB7CgkJcHJpbnRmKCIlbGxkICIsIHgtPmtleSk7CgkJcHJlb3JkZXIoeC0+bGVmdCk7CgkJcHJlb3JkZXIoeC0+cmlnaHQpOwoJfQoJLy9wdXRjaGFyKCdcbicpOwp9CgpOT0RFUFRSIHNlYXJjaChOT0RFUFRSIHJvb3QsIGxvbmcgbG9uZyBrKSB7CglpZiAocm9vdCA9PSBOSUxQVFIgfHwgcm9vdC0+a2V5ID09IGspCgkJcmV0dXJuIHJvb3Q7CglpZiAoayA8IHJvb3QtPmtleSkKCQlyZXR1cm4gc2VhcmNoKHJvb3QtPmxlZnQsIGspOwoJZWxzZQoJCXJldHVybiBzZWFyY2gocm9vdC0+cmlnaHQsIGspOwp9CgpOT0RFUFRSIG1pbmltdW0oTk9ERVBUUiByb290KSB7Cgl3aGlsZSAocm9vdC0+bGVmdCAhPSBOSUxQVFIpCgkJcm9vdCA9IHJvb3QtPmxlZnQ7CglyZXR1cm4gcm9vdDsKfQoKTk9ERVBUUiBtYXhpbXVtKE5PREVQVFIgcm9vdCkgewoJd2hpbGUgKHJvb3QtPnJpZ2h0ICE9IE5JTFBUUikKCQlyb290ID0gcm9vdC0+cmlnaHQ7CglyZXR1cm4gcm9vdDsKfQoKTk9ERVBUUiBzdWNjZXNzb3IoTk9ERVBUUiByb290LCBsb25nIGxvbmcgeCkgewoJTk9ERVBUUiB0ZW1wID0gc2VhcmNoKHJvb3QsIHgpOwoJaWYgKHRlbXAgPT0gTklMUFRSKSB7CgkJcHJpbnRmKCIlbGxkIG5vdCBpbiB0cmVlXG4iLCB4KTsKCQlyZXR1cm4gdGVtcDsKCX0KCWlmICh0ZW1wLT5yaWdodCAhPSBOSUxQVFIpCgkJcmV0dXJuIG1pbmltdW0odGVtcC0+cmlnaHQpOwoJTk9ERVBUUiB5ID0gdGVtcC0+cDsKCXdoaWxlICh5ICE9IE5JTFBUUiAmJiB0ZW1wID09IHktPnJpZ2h0KSB7CgkJdGVtcCA9IHk7CgkJeSA9IHktPnA7Cgl9CglyZXR1cm4geTsKfQoKTk9ERVBUUiBwcmVkZWNlc3NvcihOT0RFUFRSIHJvb3QsIGxvbmcgbG9uZyB4KSB7CglOT0RFUFRSIHRlbXAgPSBzZWFyY2gocm9vdCwgeCk7CglpZiAodGVtcCA9PSBOSUxQVFIpIHsKCQlwcmludGYoIiVsbGQgbm90IGluIHRyZWVcbiIsIHgpOwoJCXJldHVybiB0ZW1wOwoJfQoJaWYgKHRlbXAtPmxlZnQgIT0gTklMUFRSKQoJCXJldHVybiBtYXhpbXVtKHRlbXAtPmxlZnQpOwoJTk9ERVBUUiB5ID0gdGVtcC0+cDsKCXdoaWxlICh5ICE9IE5JTFBUUiAmJiB0ZW1wID09IHktPmxlZnQpIHsKCQl0ZW1wID0geTsKCQl5ID0geS0+cDsKCX0KCXJldHVybiB5Owp9CnZvaWQgbGVmdHJvdGF0ZShOT0RFUFRSICp0cmVlcm9vdCwgTk9ERVBUUiB4KSB7CglOT0RFUFRSIHkgPSB4LT5yaWdodDsKCXgtPnJpZ2h0ID0geS0+bGVmdDsKCWlmICh5LT5sZWZ0ICE9IE5JTFBUUikKCQl5LT5sZWZ0LT5wID0geDsKCXktPnAgPSB4LT5wOwoJaWYgKHgtPnAgPT0gTklMUFRSKQoJCSp0cmVlcm9vdCA9IHk7CgllbHNlIGlmICh4LT5wLT5sZWZ0ID09IHgpCgkJeC0+cC0+bGVmdCA9IHk7CgllbHNlCgkJeC0+cC0+cmlnaHQgPSB5OwoJeS0+bGVmdCA9IHg7Cgl4LT5wID0geTsKCXktPnNpemUgPSB4LT5zaXplOwoJeC0+c2l6ZSA9IHgtPmxlZnQtPnNpemUgKyB4LT5yaWdodC0+c2l6ZSArMTsKfQoKdm9pZCByaWdodHJvdGF0ZShOT0RFUFRSICp0cmVlcm9vdCwgTk9ERVBUUiB5KSB7CglOT0RFUFRSIHggPSB5LT5sZWZ0OwoJeS0+bGVmdCA9IHgtPnJpZ2h0OwoJaWYgKHgtPnJpZ2h0ICE9IE5JTFBUUikKCQl4LT5yaWdodC0+cCA9IHk7Cgl4LT5wID0geS0+cDsKCWlmICh5LT5wID09IE5JTFBUUikKCQkqdHJlZXJvb3QgPSB4OwoJZWxzZSBpZiAoeS0+cC0+bGVmdCA9PSB5KQoJCXktPnAtPmxlZnQgPSB4OwoJZWxzZQoJCXktPnAtPnJpZ2h0ID0geDsKCXgtPnJpZ2h0ID0geTsKCXktPnAgPSB4OwoJeC0+c2l6ZSA9IHktPnNpemU7Cgl5LT5zaXplID0geS0+bGVmdC0+c2l6ZSArIHktPnJpZ2h0LT5zaXplICsgMTsKfQoKdm9pZCByYmluc2VydGZpeHVwKE5PREVQVFIgKnRyZWVyb290LCBOT0RFUFRSIHopIHsKCXdoaWxlICh6LT5wLT5jb2xvciA9PSBSRUQpIHsKCQlpZiAoei0+cCA9PSB6LT5wLT5wLT5sZWZ0KSB7CgkJCU5PREVQVFIgeSA9IHotPnAtPnAtPnJpZ2h0OwoJCQlpZiAoeS0+Y29sb3IgPT0gUkVEKSB7CgkJCQl6LT5wLT5jb2xvciA9IEJMQUNLOwoJCQkJeS0+Y29sb3IgPSBCTEFDSzsKCQkJCXotPnAtPnAtPmNvbG9yID0gUkVEOwoJCQkJeiA9IHotPnAtPnA7CgkJCX0KCQkJZWxzZSB7CgkJCQlpZiAoeiA9PSB6LT5wLT5yaWdodCkgewoJCQkJCXogPSB6LT5wOwoJCQkJCWxlZnRyb3RhdGUodHJlZXJvb3Qseik7CgkJCQl9CgkJCQl6LT5wLT5jb2xvciA9IEJMQUNLOwoJCQkJei0+cC0+cC0+Y29sb3IgPSBSRUQ7CgkJCQlyaWdodHJvdGF0ZSh0cmVlcm9vdCx6LT5wLT5wKTsKCQkJfQoJCX0KCQllbHNlIHsKCQkJTk9ERVBUUiB5ID0gei0+cC0+cC0+bGVmdDsKCQkJaWYgKHktPmNvbG9yID09IFJFRCkgewoJCQkJei0+cC0+Y29sb3IgPSBCTEFDSzsKCQkJCXktPmNvbG9yID0gQkxBQ0s7CgkJCQl6LT5wLT5wLT5jb2xvciA9IFJFRDsKCQkJCXogPSB6LT5wLT5wOwoJCQl9CgkJCWVsc2UgewoJCQkJaWYgKHogPT0gei0+cC0+bGVmdCkgewoJCQkJCXogPSB6LT5wOwoJCQkJCXJpZ2h0cm90YXRlKHRyZWVyb290LHopOwoJCQkJfQoJCQkJei0+cC0+Y29sb3IgPSBCTEFDSzsKCQkJCXotPnAtPnAtPmNvbG9yID0gUkVEOwoJCQkJbGVmdHJvdGF0ZSh0cmVlcm9vdCx6LT5wLT5wKTsKCQkJfQoJCX0KCX0KCSgqdHJlZXJvb3QpLT5jb2xvciA9IEJMQUNLOwp9Cgp2b2lkIHJiaW5zZXJ0KE5PREVQVFIgKnRyZWVyb290LCBsb25nIGxvbmcgeikgewoJTk9ERVBUUiBaID0gKE5PREVQVFIpIG1hbGxvYyhzaXplb2Yoc3RydWN0IG5vZGUpKTsKCVotPmtleSA9IHo7CglOT0RFUFRSIHkgPSBOSUxQVFI7CglOT0RFUFRSIHggPSAqdHJlZXJvb3Q7Cgl3aGlsZSAoeCAhPSBOSUxQVFIpIHsKCQl5ID0geDsKCQl5LT5zaXplKys7CgkJaWYgKFotPmtleSA8IHgtPmtleSkKCQkJeCA9IHgtPmxlZnQ7CgkJZWxzZSBpZiAoWi0+a2V5ID4geC0+a2V5KQoJCQl4ID0geC0+cmlnaHQ7CgkJZWxzZSB7CgkJCU5PREVQVFIgdGVtcCA9IHg7CgkJCXdoaWxlICh4ICE9IE5JTFBUUikgewoJCQkJeC0+c2l6ZS0tOwoJCQkJeCA9IHgtPnA7CgkJCX0KCQkJZnJlZShaKTsKCQkJcmV0dXJuOwoJCX0KCX0KCVotPnAgPSB5OwoJaWYgKHkgPT0gTklMUFRSKQoJCSp0cmVlcm9vdCA9IFo7CgllbHNlIGlmIChaLT5rZXkgPCB5LT5rZXkpCgkJeS0+bGVmdCA9IFo7CgllbHNlCgkJeS0+cmlnaHQgPSBaOwoJWi0+bGVmdCA9IE5JTFBUUjsKCVotPnJpZ2h0ID0gTklMUFRSOwoJWi0+Y29sb3IgPSBSRUQ7CglaLT5zaXplID0gMTsKCXJiaW5zZXJ0Zml4dXAodHJlZXJvb3QsWik7Cn0KCnZvaWQgcmJ0cmFuc3BsYW50KE5PREVQVFIgKnRyZWVyb290LCBOT0RFUFRSIHUsIE5PREVQVFIgdikgewoJaWYgKHUtPnAgPT0gTklMUFRSKQoJCSp0cmVlcm9vdCA9IHY7CgllbHNlIGlmICh1ID09IHUtPnAtPmxlZnQpCgkJdS0+cC0+bGVmdCA9IHY7CgllbHNlCgkJdS0+cC0+cmlnaHQgPSB2OwoJdi0+cCA9IHUtPnA7Cn0KCnZvaWQgcmJkZWxldGVmaXh1cChOT0RFUFRSICp0cmVlcm9vdCwgTk9ERVBUUiB4KSB7Cgl3aGlsZSAoeCAhPSAqdHJlZXJvb3QgJiYgeC0+Y29sb3IgPT0gQkxBQ0spIHsKCQlpZiAoeCA9PSB4LT5wLT5sZWZ0KSB7CgkJCU5PREVQVFIgdyA9IHgtPnAtPnJpZ2h0OwoJCQlpZiAody0+Y29sb3IgPT0gUkVEKSB7CgkJCQl3LT5jb2xvciA9IEJMQUNLOwoJCQkJeC0+cC0+Y29sb3IgPSBSRUQ7CgkJCQlsZWZ0cm90YXRlKHRyZWVyb290LHgtPnApOwoJCQkJdyA9IHgtPnAtPnJpZ2h0OwoJCQl9CgkJCWlmICh3LT5sZWZ0LT5jb2xvciA9PSBCTEFDSyAmJiB3LT5yaWdodC0+Y29sb3IgPT0gQkxBQ0spIHsKCQkJCXctPmNvbG9yID0gUkVEOwoJCQkJeCA9IHgtPnA7CgkJCX0KCQkJZWxzZSB7CgkJCSAJaWYgKHctPnJpZ2h0LT5jb2xvciA9PSBCTEFDSykgewoJCQkJCXctPmxlZnQtPmNvbG9yID0gQkxBQ0s7CgkJCQkJdy0+Y29sb3IgPSBSRUQ7CgkJCQkJcmlnaHRyb3RhdGUodHJlZXJvb3Qsdyk7CgkJCQkJdyA9IHgtPnAtPnJpZ2h0OwoJCQkJfQoJCQkJdy0+Y29sb3IgPSB4LT5wLT5jb2xvcjsKCQkJCXgtPnAtPmNvbG9yID0gQkxBQ0s7CgkJCQl3LT5yaWdodC0+Y29sb3IgPSBCTEFDSzsKCQkJCWxlZnRyb3RhdGUodHJlZXJvb3QseC0+cCk7CgkJCQl4ID0gKnRyZWVyb290OwoJCQl9CgkJfQoJCWVsc2UgewoJCQlOT0RFUFRSIHcgPSB4LT5wLT5sZWZ0OwoJCQlpZiAody0+Y29sb3IgPT0gUkVEKSB7CgkJCQl3LT5jb2xvciA9IEJMQUNLOwoJCQkJeC0+cC0+Y29sb3IgPSBSRUQ7CgkJCQlyaWdodHJvdGF0ZSh0cmVlcm9vdCx4LT5wKTsKCQkJCXcgPSB4LT5wLT5sZWZ0OwoJCQl9CgkJCWlmICh3LT5sZWZ0LT5jb2xvciA9PSBCTEFDSyAmJiB3LT5yaWdodC0+Y29sb3IgPT0gQkxBQ0spIHsKCQkJCXctPmNvbG9yID0gUkVEOwoJCQkJeCA9IHgtPnA7CgkJCX0KCQkJZWxzZSB7CgkJCQlpZiAody0+bGVmdC0+Y29sb3IgPT0gQkxBQ0spIHsKCQkJCQl3LT5yaWdodC0+Y29sb3IgPSBCTEFDSzsKCQkJCQl3LT5jb2xvciA9IFJFRDsKCQkJCQlsZWZ0cm90YXRlKHRyZWVyb290LHcpOwoJCQkJCXcgPSB4LT5wLT5sZWZ0OwoJCQkJfQoJCQkJdy0+Y29sb3IgPSB4LT5wLT5jb2xvcjsKCQkJCXgtPnAtPmNvbG9yID0gQkxBQ0s7CgkJCQl3LT5sZWZ0LT5jb2xvciA9IEJMQUNLOwoJCQkJcmlnaHRyb3RhdGUodHJlZXJvb3QseC0+cCk7CgkJCQl4ID0gKnRyZWVyb290OwoJCQl9CgkJfQoJfQoJeC0+Y29sb3IgPSBCTEFDSzsKfQoKdm9pZCByYmRlbGV0ZShOT0RFUFRSICp0cmVlcm9vdCwgbG9uZyBsb25nIHopIHsKCU5PREVQVFIgWiA9IHNlYXJjaCgqdHJlZXJvb3QsIHopOwoJaWYgKFogPT0gTklMUFRSKSB7CgkJLy9wcmxvbmcgbG9uZ2YoIk5vZGUgdG8gYmUgZGVsZXRlZCBub3QgZm91bmRcbiIpOwoJCXJldHVybjsKCX0KCU5PREVQVFIgdG1wID0gWi0+cDsKCXdoaWxlICh0bXAgIT0gTklMUFRSKSB7CgkJdG1wLT5zaXplLS07CgkJdG1wID0gdG1wLT5wOwoJfQoJTk9ERVBUUiB5ID0gWjsKCWxvbmcgbG9uZyB5b2MgPSB5LT5jb2xvcjsKCU5PREVQVFIgeDsKCWlmIChaLT5sZWZ0ID09IE5JTFBUUikgewoJCXggPSBaLT5yaWdodDsKCQlyYnRyYW5zcGxhbnQodHJlZXJvb3QsWixaLT5yaWdodCk7Cgl9CgllbHNlIGlmIChaLT5yaWdodCA9PSBOSUxQVFIpIHsKCQl4ID0gWi0+bGVmdDsKCQlyYnRyYW5zcGxhbnQodHJlZXJvb3QsWixaLT5sZWZ0KTsKCX0KCWVsc2UgewoJCXkgPSBtaW5pbXVtKFotPnJpZ2h0KTsKCQl5b2MgPSB5LT5jb2xvcjsKCQl4ID0geS0+cmlnaHQ7CgkJaWYgKHktPnAgPT0gWikKCQkJeC0+cCA9IHk7CgkJZWxzZSB7CgkJCXJidHJhbnNwbGFudCh0cmVlcm9vdCx5LHktPnJpZ2h0KTsKCQkJeS0+cmlnaHQgPSBaLT5yaWdodDsKCQkJeS0+cmlnaHQtPnAgPSB5OwoJCX0KCQlyYnRyYW5zcGxhbnQodHJlZXJvb3QsWix5KTsKCQl5LT5sZWZ0ID0gWi0+bGVmdDsKCQl5LT5sZWZ0LT5wID0geTsKCQl5LT5jb2xvciA9IFotPmNvbG9yOwoJfQoJaWYgKHlvYyA9PSBCTEFDSykKCQlyYmRlbGV0ZWZpeHVwKHRyZWVyb290LHgpOwp9Ck5PREVQVFIga3RoKE5PREVQVFIgdHJlZXJvb3QsIGxvbmcgbG9uZyBLKSB7Cglsb25nIGxvbmcgY3VycnJhbmsgPSB0cmVlcm9vdC0+bGVmdC0+c2l6ZSArIDE7CglOT0RFUFRSIHkgPSB0cmVlcm9vdDsKCXdoaWxlICh5ICE9IE5JTFBUUiAmJiBjdXJycmFuayAhPSBLKSB7CgkJaWYgKEsgPCBjdXJycmFuaykKCQkJeSA9IHktPmxlZnQ7CgkJZWxzZSB7CgkJCUsgPSBLIC0gY3VycnJhbms7CgkJCXkgPSB5LT5yaWdodDsKCQl9CgkJaWYgKHkgPT0gTklMUFRSKQoJCQlyZXR1cm4gTklMUFRSOwoJCWN1cnJyYW5rID0geS0+bGVmdC0+c2l6ZSArIDE7Cgl9CglyZXR1cm4geTsKfQoKbG9uZyBsb25nIGNudChOT0RFUFRSIHRyZWVyb290LCBsb25nIGxvbmcgeCkgewoJbG9uZyBsb25nIGFucyA9IDA7CglOT0RFUFRSIHkgPSB0cmVlcm9vdDsKCXdoaWxlICh5ICE9IE5JTFBUUikgewoJCWlmICh5LT5rZXkgPiB4KQoJCQl5ID0geS0+bGVmdDsKCQllbHNlIGlmICh5LT5rZXkgPCB4KSB7CgkJCWFucyArPSB5LT5sZWZ0LT5zaXplICsgMTsKCQkJeSA9IHktPnJpZ2h0OwoJCX0KCQllbHNlIAoJCQlyZXR1cm4gYW5zICsgeS0+bGVmdC0+c2l6ZTsKCX0KCXJldHVybiBhbnM7Cn0KCm1haW4oKQp7CglOSUwubGVmdCA9IE5JTC5yaWdodCA9IE5JTC5wID0gTklMUFRSOwoJTklMLmNvbG9yID0gQkxBQ0s7CglOT0RFUFRSIHRyZWUgPSBOSUxQVFI7Cglsb25nIGxvbmcgUTsKCWxvbmcgbG9uZyB4LCBrOwoJTk9ERVBUUiB0ZW1wOwoJY2hhciBjWzJdOwoJc2NhbmYoIiVsbGQiLCAmUSk7CglnZXRjaGFyKCk7Cgl3aGlsZSAoUS0tKSB7CgkJc2NhbmYoIiVzIiwgYyk7CgkJc3dpdGNoIChjWzBdKSB7CgkJCWNhc2UgJ0knOgoJCQkJc2NhbmYoIiVsbGQiLCAmeCk7CgkJCQlyYmluc2VydCgmdHJlZSwgeCk7CgkJCQlicmVhazsKCQkJY2FzZSAnRCc6CgkJCQlzY2FuZigiJWxsZCIsICZ4KTsKCQkJCXJiZGVsZXRlKCZ0cmVlLCB4KTsKCQkJCWJyZWFrOwoJCQljYXNlICdLJzoKCQkJCXNjYW5mKCIlbGxkIiwgJmspOwoJCQkJdGVtcCA9IGt0aCh0cmVlLCBrKTsKCQkJCWlmICh0ZW1wICE9IE5JTFBUUikKCQkJCQlwcmludGYoIiVsbGRcbiIsIHRlbXAtPmtleSk7CgkJCQllbHNlCgkJCQkJcHJpbnRmKCJpbnZhbGlkXG4iKTsKCQkJCWJyZWFrOwoJCQljYXNlICdDJzoKCQkJCXNjYW5mKCIlbGxkIiwgJngpOwoJCQkJcHJpbnRmKCIlbGxkXG4iLCBjbnQodHJlZSx4KSk7CgkJCQlicmVhazsKCQkJZGVmYXVsdDoKCQkJCWJyZWFrOwoJCX0KCX0KCS8qaW5vcmRlcih0cmVlKTsKCXB1dGNoYXIoJ1xuJyk7CglwcmVvcmRlcih0cmVlKTsKCXB1dGNoYXIoJ1xuJyk7Ki8KCXJldHVybiAwOwp9Cg==