Здравствуйте! Есть такая задача: Есть объекты, их нужно распределить на 2 множества. Вводятся условия типа эти 2 объекта точно лежат/не лежат в одно множестве. Нужно такие запросы обрабатывать в онлайн и проверять на противоречивость. И еще нужно уметь по запросу выводить корректный пример разбиения. Хочу предложить такой метод решения данной задачи: Создадим СНМ из 2*n множеств. Каждой вершине соответствуют 2 множества 2*i и 2*i+1. В множестве 2*i лежат вершины которые точно находятся в одном множестве с i, а в множестве i*2+1 те, которые точно не в одном множестве с i. Таким образом утверждается что запрос "вершины a и b лежат в одном множестве" сводится к unite(a*2, b*2) и unite(a*2+1, b*2+1). А запрос "вершины a и b не лежат в одном множестве" сводится к unite(a*2, b*2+1) и unite(a*2+1, b*2). Утверждается, что при этих операциях свойство про то, что в множестве 2*i лежат вершины которые точно находятся в одном множестве с i, а в множестве i*2+1 те, которые точно не в одном множестве с i, будет соблюдаться, т.к. несложно заметить, что i*2 и i*2+1 всегда имеют одинаковые ранги. Вот исходный код решения: http://pastebin.com/6z1dvy2Q. Что вы думаете по этому поводу? Существуют ли альтернативные алгоритмы? Можно ли решить задачу быстрее(обязательно онлайн)?
Можно избавиться от второго СНМа, но зато добавить для каждой вершины параметр, который будет означать следующее: находится ли эта вершина в той же доле, что и ее предок в дереве непересекающихся множеств. Дальше додумывай самостоятельно :).
А насчет "быстрее" — вроде бы нельзя. Во всяком случае, если к перечисленным тобой запросам добавить запрос "отменить последнее добавление" — тогда точно нельзя, потому что к такой задаче тривиально сводится за линейное время задача о поддержании системы непересекающихся множеств. А для СНМ была доказана нижняя граница Ω(N * α(N)).
А зачем избавляться от второго СНМа? Так код получается простой и краткий. И преимущество в производительности там вряд ли будет. А разве без отмены последнего действия не сводится?
В-принципе, незачем, это я просто рассказал еще одну идею решения задачи.
А как свести без отмены последнего действия? Я, например, не понимаю, как без нее отвечать на запрос SameSet(v1, v2). Кстати, даже так получается не совсем полноценное сведение — мы не можем реализовать запрос FindSet(v).
Unite(a, b) будет dsu_unite_same(a, b). А find(a) будет dsu_find(a*2)/2.