#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const string invalid="Invalid command";
const string ok="OK";
struct Node
{
string name;
map<string, Node*> children;
Node* parent;
int size;
Node(string name)
{
this->name=name;
parent=nullptr;
size=1;
}
};
vector<string> splitPath(string& path)
{
vector<string> parts;
stringstream ss(path);
string part;
while (getline(ss, part, '/'))
{
if (!part.empty()) {
parts.push_back(part);
}
}
return parts;
}
vector<string> splitCommand(string& command)
{
vector<string> parts;
stringstream ss(command);
string part;
// while (ss >> part) {
// parts.push_back(part);
// }
while(getline(ss,part,' '))
{
if(!part.empty()) parts.push_back(part);
}
return parts;
}
class Tree
{
private:
Node* root;
int totalNodes;
Node* getNode(vector<string>& parts) //o log n
{
if (parts.empty() || parts[0] != root->name) return nullptr;
Node* current = root;
for (int i = 1; i < parts.size(); i++)
{
auto it = current->children.find(parts[i]);
if (it == current->children.end()) return nullptr;
current = it->second;
}
return current;
}
bool isAncestor(Node* src, Node* dest) //o log n
{
Node* current = dest;
while (current != nullptr)
{
if (current == src) return true;
current = current->parent;
}
return false;
}
Node* copyTree(Node* src) //o(n)
{
Node* copy = new Node(src->name);
copy->size = src->size;
totalNodes++;
for (auto& c : src->children)
{
Node* childCopy = copyTree(c.second);
childCopy->parent = copy;
copy->children[c.first] = childCopy;
}
return copy;
}
void computeSizes(Node* node) //o(n)
{
// if (!node) return;
node->size = 1;
for (auto& c : node->children)
{
computeSizes(c.second);
node->size += c.second->size;
}
}
public:
Tree(vector<string>& lines)
{
if (lines.empty())
{
root = nullptr;
totalNodes = 0;
return;
}
string firstLine = lines[0];
vector<string> tokens = splitCommand(firstLine);
if (tokens.empty())
{
root = nullptr;
totalNodes = 0;
return;
}
root = new Node(tokens[0]);
totalNodes = 1;
for (int i = 1; i < tokens.size(); ++i)
{
Node* child = new Node(tokens[i]);
child->parent = root;
root->children[tokens[i]] = child;
totalNodes++;
}
for (int i = 1; i < lines.size(); ++i)
{
tokens = splitCommand(lines[i]);
if (tokens.empty()) continue;
string parentPath = tokens[0];
vector<string> parentParts = splitPath(parentPath);
Node* parentNode = getNode(parentParts);
if (!parentNode) continue;
for (int j = 1; j < tokens.size(); j++) {
string childName = tokens[j];
if (parentNode->children.count(childName)) continue;
Node* child = new Node(childName);
child->parent = parentNode;
parentNode->children[childName] = child;
totalNodes++;
}
}
computeSizes(root);
}
//Possible that someone may have added a subtree to this node.
//Another possibility is the removal of subtree from any child of this node.
//TC-> o(length of path) -> o(log n)
string countDescendants(string& path)
{
vector<string> parts = splitPath(path);
Node* node = getNode(parts);
if (!node) return invalid;
return to_string(node->size - 1);
}
//
string cutPaste(string& src, string& dest) //O(log N)
{
vector<string> srcParts = splitPath(src);//length of path-> log n
vector<string> destParts = splitPath(dest);
Node* srcNode = getNode(srcParts);
Node* destNode = getNode(destParts);
if (!srcNode || !destNode) return invalid;
if (srcNode == destNode) return invalid;
if (isAncestor(srcNode, destNode)) return invalid;//o log n
// if(isAncestor(destNode,srcNode)) return invalid;// log n
//do we need to check this?
if (destNode->children.count(srcNode->name)) return invalid;
//actual work starts here
//remove node from previous parent
Node* oldParent = srcNode->parent;
if (!oldParent) return invalid;
oldParent->children.erase(srcNode->name);//o log(children)
int diff = srcNode->size;
Node* current = oldParent;
while (current) //o log n
{
current->size -= diff;
current = current->parent;
}
//add node to new parent ie destination
srcNode->parent = destNode;
destNode->children[srcNode->name] = srcNode; //o log (children)
current = destNode;
while (current)//o(logn)
{
current->size += diff;
current = current->parent;
}
return ok;
}
string copyPaste(string& src, string& dest) //o(n)
{
vector<string> srcParts = splitPath(src);
vector<string> destParts = splitPath(dest);
Node* srcNode = getNode(srcParts);
Node* destNode = getNode(destParts);
if (!srcNode || !destNode) return invalid;
if (isAncestor(srcNode, destNode)) return invalid;
// if(isAncestor(destNode,srcNode)) return invalid;
if (destNode->children.count(srcNode->name)) return invalid;
if (totalNodes + srcNode->size > 1e6) return invalid;
//copy tree
Node* copiedSubtree = copyTree(srcNode);//O(n);// number of desc.
destNode->children[copiedSubtree->name] = copiedSubtree;
copiedSubtree->parent = destNode;
int diff = copiedSubtree->size;
Node* current = destNode;
while (current)
{
current->size += diff;
current = current->parent;
}
totalNodes += srcNode->size;
return ok;
}
};
int main()
{
// ios_base::sync_with_stdio(false);
// cin.tie(nullptr);
int n, q;
cin >> n >> q;
cin.ignore();
vector<string> lines(n);
for (int i = 0; i < n; ++i)
{
string line;
getline(cin, line);
lines[i] = line;
}
Tree tree(lines);
for (int i = 0; i < q; ++i)
{
string command;
getline(cin, command);
vector<string> parts = splitCommand(command);
if (parts.empty()) {
cout << invalid << endl;
continue;
}
string cmd = parts[0];
if (cmd == "countDescendants")
{
if (parts.size() != 2) {
cout << invalid << endl;
} else {
cout << tree.countDescendants(parts[1]) << endl;
}
} else if (cmd == "cutPaste") {
if (parts.size() != 3) {
cout << invalid << endl;
} else {
cout << tree.cutPaste(parts[1], parts[2]) << endl;
}
} else if (cmd == "copyPaste") {
if (parts.size() != 3) {
cout << invalid << endl;
} else {
cout << tree.copyPaste(parts[1], parts[2]) << endl;
}
} else {
cout << invalid << endl;
}
}
return 0;
}