/** Solution for Season 6 Round 4 Problem 5 Senior Author: Anton Chernev */ #include #include #include using namespace std; const int MAX_N = 100100, MAX_digits = 500500; struct treap { int key; int priority; int treeSize; treap *left, *right; treap(int _key) { key = _key; priority = rand(); treeSize = 1; left = right = NULL; } }; inline int getTreeSize(treap *root) { return root ? root->treeSize : 0; } void updateSize(treap *root) { if(root) root->treeSize = getTreeSize(root->left) + getTreeSize(root->right) + 1; } void Split(treap *root, treap *&leftPart, treap *&rightPart, int key) { if(!root) leftPart = rightPart = 0; else if(root->key <= key) { Split(root->right, root->right, rightPart, key); leftPart = root; } else { Split(root->left, leftPart, root->left, key); rightPart = root; } updateSize(root); } void Merge(treap *&newRoot, treap *root1, treap *root2) { if(!root1 || !root2) newRoot = root1 ? root1 : root2; else if(root1->key < root2->key) { Merge(root1->right, root1->right, root2); newRoot = root1; } else { Merge(root2->left, root1, root2->left); newRoot = root2; } updateSize(newRoot); } void Insert(treap *&root, treap *element) { if(!root) root = element; else if(root->priority < element->priority) { Split(root, element->left, element->right, element->key); root = element; } else Insert(element->key <= root->key ? root->left : root->right, element); updateSize(root); } void Erase(treap *&root, int key) { if(!root) return; if(key == root->key) { treap *unusedPointer = root; Merge(root, root->left, root->right); delete unusedPointer; } else Erase(key < root->key ? root->left : root->right, key); updateSize(root); } void printTreap(treap *root) { if(!root) return; printf("print treap: %d\n", root->key); printTreap(root->left); printTreap(root->right); } int GreaterOrEqual(treap *root, int key) { if(!root) return 0; //printf("in treap %d\n", root->key); if(root->key < key) return GreaterOrEqual(root->right, key); return getTreeSize(root->right) + 1 + GreaterOrEqual(root->left, key); } struct segment { int leftEnd, rightEnd; treap *values; segment *leftSegment, *rightSegment; segment(int _leftEnd, int _rightEnd) { leftEnd = _leftEnd; rightEnd = _rightEnd; values = NULL; leftSegment = NULL; rightSegment = NULL; } }; int M, N; int input[MAX_digits], digits[MAX_digits]; int p[MAX_N]; segment *mainRoot; void Swap(int &x, int &y) { int z = x; x = y; y = z; } void read() { char digit; scanf("%c", &digit); while(digit != '\n') { input[++M] = digit - '0'; scanf("%c", &digit); } for(int i = 1; i <= M; i++) digits[i] = input[M - i + 1]; scanf("%d", &N); for(int i = 1; i <= N; i++) scanf("%d", &p[i]); } void buildTree(segment *&root, int leftEnd, int rightEnd) { root = new segment(leftEnd, rightEnd); treap *element; for(int i = leftEnd; i <= rightEnd; i++) { element = new treap(p[i]); Insert(root->values, element); } if(leftEnd == rightEnd) return; buildTree(root->leftSegment, leftEnd, (leftEnd + rightEnd) / 2); buildTree(root->rightSegment, (leftEnd + rightEnd) / 2 + 1, rightEnd); //Unite(root->values, root->leftSegment->values, root->rightSegment->values); } int findInTree(segment *root, int leftEnd, int rightEnd, int key) { if(leftEnd > root->rightEnd || root->leftEnd > rightEnd) return 0; if(leftEnd <= root->leftEnd && root->rightEnd <= rightEnd) { //printf("!!!%d %d %d\n", root->leftEnd, root->rightEnd, GreaterOrEqual(root->values, key)); //if(root->leftEnd == 2 && root->rightEnd == 2) // printTreap(root->values); return GreaterOrEqual(root->values, key); } return findInTree(root->leftSegment, leftEnd, rightEnd, key) + findInTree(root->rightSegment, leftEnd, rightEnd, key); } void update(segment *root, int pos, int oldValue, int newValue) { Erase(root->values, oldValue); treap *element = new treap(newValue); Insert(root->values, element); //if(newValue == 10) printf("updated with 10: %d %d\n", root->leftEnd, root->rightEnd); if(root->leftEnd == root->rightEnd) return; update(pos <= root->leftSegment->rightEnd ? root->leftSegment : root->rightSegment, pos, oldValue, newValue); } int computePower(int x, int y) { if(!y) return 1; if(y % 2) return x * computePower(x, y - 1) % 10; else { int tmp = computePower(x, y / 2); return tmp * tmp % 10; } } void answerQueries() { int Q; int x, y, z; int power, answer; scanf("%d", &Q); for(int i = 1; i <= Q; i++) { scanf("%d%d", &x, &y); if(y == 1) printf("%d\n", digits[x]); else { power = findInTree(mainRoot, 2, y, x); //printf("power is: %d answer is ", power); answer = (digits[x] * computePower(2, power)) % 10; printf("%d\n", answer); update(mainRoot, y, p[y], p[1]); Swap(p[1], p[y]); } } } int main() { srand(420); read(); buildTree(mainRoot, 2, N); answerQueries(); }