Здравствуйте, У меня возникла проблема я когда прочитал и понял как использовать персистентное декартого дерево спотокнулся над одной проблемы. Мы знаем что с помощью персистентной декарткой мы мoжем скопировать отрезок в другой часть массива. Но именно эту операцию я не понял как сделать, и не где не нашел где об этом было рассказано. В простом декартово дерево моя идея заключалась в том что, надо копировать все дерево а потом вырезать отрезак которе мы хотим скопировать у первого дерево, а отрезок где мы хотим вставить наш скопированный отрезок у второго дерево. И потом эти отрезки swap. оставляем второе дерево, а первый больше не нужен. помогите пожалуйста, зарание спасибо!
Вот реализация персистентной дерамиды! Oно работает!
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
struct Node {
long long int val;
int cnt;
long long int sum;
int link;
Node *l; Node *r;
Node() {
link = 0;
val = 0;
cnt = 0;
sum = 0;
l = r = 0;
}
Node(long long int va) {
val = va;
cnt = 1;
sum = va;
link = 0;
l = r = 0;
}
Node(Node *t) {
if (t == 0) {
return;
}
val = t -> val;
cnt = t -> cnt;
sum = t -> sum;
link = 0;
l = t -> l;
r = t -> r;
}
};
int N;
long long int X1, A, B, M;
int K;
void AddLink(Node *t) {
if (t == 0) {
return;
}
t -> link++;
}
void DelNode(Node *t) {
if (t == 0) {
return;
}
t -> link--;
if (t -> link <= 0) {
DelNode(t -> l);
DelNode(t -> r);
delete t;
}
}
int cntt(Node *t) {
if (t == 0) {
return 0;
}
return t -> cnt;
}
long long int ssum(Node *t) {
if (t == 0) {
return 0;
}
return t -> sum;
}
void update(Node *t) {
if (t != 0) {
t -> cnt = cntt(t -> r) + cntt(t -> l) + 1;
t -> sum = ssum(t -> r) + ssum(t -> l) + t -> val;
}
}
Node *merge_t(Node *L, Node *R) {
Node *ptrn = 0;
if (L == 0) {
ptrn = new Node(R);
AddLink(ptrn -> l);
AddLink(ptrn -> r);
return ptrn;
}
if (R == 0) {
ptrn = new Node(L);
AddLink(ptrn -> l);
AddLink(ptrn -> r);
return ptrn;
}
if ((rand() % (L -> cnt + R -> cnt)) > R -> cnt) {
ptrn = new Node(L);
ptrn -> r = merge_t(ptrn -> r, R);
AddLink(ptrn -> l);
AddLink(ptrn -> r);
update(ptrn);
return ptrn;
} else {
ptrn = new Node(R);
ptrn -> l = merge_t(L, ptrn -> l);
AddLink(ptrn -> l);
AddLink(ptrn -> r);
update(ptrn);
return ptrn;
}
}
void split_t(Node *t, int x, Node *&L, Node *&R) {
if (t == 0) {
L = R = 0;
return;
}
Node *cur = new Node(t);
int indexx = cntt(t -> l) + 1;
if (indexx <= x) {
split_t(cur -> r, x - indexx, cur -> r, R);
AddLink(cur -> l);
AddLink(cur -> r);
L = cur;
} else {
split_t(cur -> l, x, L, cur -> l);
AddLink(cur -> l);
AddLink(cur -> r);
R = cur;
}
update(L);
update(R);
}
void printt(Node *t) {
if (t == 0) {
return;
}
printt(t -> l);
printf("%lld ", t -> val);
//cout << t -> val <<" "<< t -> link << endl;
printt(t -> r);
}
int main() {
//freopen("meneger.in", "r", stdin);
//freopen("meneger.out", "w", stdout);
string s;
Node *t = 0;
scanf("%d", &N);
scanf("%lld %lld %lld %lld", &X1, &A, &B, &M);
for (int i = 0; i < N; i++) {
Node *tt;
Node *nt;
if (i == 0) {
tt = new Node(X1);
nt = merge_t(t, tt);
DelNode(t);
DelNode(tt);
t = nt;
} else {
X1 = (A * X1 + B) % M;
tt = new Node(X1);
nt = merge_t(t, tt);
DelNode(t);
DelNode(tt);
t = nt;
}
}
//printt(t);
//cout << endl;
int a, b, w;
scanf("%d", &K);
for (int i = 0; i < K; i++) {
cin >> s;
if (s == "cpy") {
scanf("%d %d %d", &a, &b, &w);
a--; b--;
Node *left = 0;
Node *right = 0;
Node *lleft = 0;
Node *rright = 0;
Node *lr = 0;
Node *sr = 0;
Node *nt;
split_t(t, a, left, right);
DelNode(left);
sr = right;
split_t(right, w, left, right);
DelNode(sr);
DelNode(right);
sr = 0;
split_t(t, b, lleft, rright);
lr = lleft;
sr = rright;
split_t(rright, w, lleft, rright);
DelNode(lleft);
DelNode(sr);
Node *tnt;
nt = merge_t(lr, left);
tnt = nt;
nt = merge_t(nt, rright);
DelNode(lr);
DelNode(left);
DelNode(rright);
DelNode(tnt);
DelNode(t);
t = nt;
} else if (s == "sum") {
scanf("%d %d", &a, &b);
a--;
b -= a;
Node *left;
Node *right;
Node *sr;
split_t(t, a, left, right);
DelNode(left);
sr = right;
split_t(right, b, left, right);
DelNode(sr);
DelNode(right);
printf("%lld\n", left -> sum);
DelNode(left);
} else if (s == "out") {
scanf("%d %d", &a, &b);
a--;
b -= a;
Node *left;
Node *right;
Node *sr;
split_t(t, a, left, right);
DelNode(left);
sr = right;
split_t(right, b, left, right);
DelNode(sr);
DelNode(right);
printt(left);
printf("\n");
DelNode(left);
}
}
return 0;
}









У нас есть много версий дерева
1 версия: исходное дерево
2 версия: отрезанный кусок КОТОРЫЙ копируем
3 и 4 версия: префикс и суффикс 1 версии с вырезанным отрезком В КОТОРЫЙ копируем
Дальше просто merge'им 2, 3 и 4 версию и получаем новое дерево со скопированным отрезком
да это понятно как с простой декарткой, а как же это делать с персистентной. Потому что во первых с первым способом будет привешение лимит времени так как будем каждый раз копировать все дерево. И вторая проблема в том что если попытаешься склеить две одинаковые деревья оброзуется бомбук.
В том то и дело, что мы меняем только log вершин, поэтому ничего не копируем. Там будет уже не дерево, а ациклический орграф. То есть мы автоматически прицепим копируемый отрезок в 2 места(на самом деле может быть чуть сложнее, но так легче понять).
Во-первых, бамбук мы скорее всего не получим, потому что либо у нас просто две ссылки ведут в одну вершину и все ок, либо мы создадим новую вершину с новым приоритетом.
Во-вторых, если страшно делать так, можно в merge заменить сравнение приоритетов на
Но это дольше работает из-за вызова рандома вместо сравнения
Только не
rand()%2 == 0, аrand()%(l->size()+r->size()) < l->size().Думаю ты не до конца разобрался, при вырезании куска, мы получим какой-то новый корень этого куска, и если рассматривать весь этот вырезанный кусок, то в нем будут отличаться только O(log(n) ) вершин от исходного куска(у этих вершин будут изменены указатели на детей). Ну а если ты хочешь склеить 2 "одинаковых куска", то они будут склеиваться "вероятностно", в персистентном декартовом дереве нет приоритетов, вместо этого случайно при склеивании очередной "верхней" вершиной выбирается вершина, исходя из размеров склевываемых поддеревьев.
Может быть тебе стоит изучить более простые алгоритмы?
Куда уж проще? Укконен разве что только :D
А знаете, такие посты от серых чертовски мотивируют.
Добавлю мотивации
P.S. Хотя очевидно, что он сдал решение Петра. Зачем, интересно?
А давать ссылку на код уже не модно?
Нынче в моде QR-коды на спине, а не какие то ссылки =)
Мдааа, юзать vector.erase и vector.insert уже не модно?
Навалил всякой фигни, не зная очевидных вещей вроде vector)))
А асимптотика в O(n) на операцию и квадратичное использование памяти (из-за персистентности, ну или линейная память и какой-нибудь логарифм на запрос), типа, модно?
чел ты...