#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <set>
#include <x86intrin.h>
#include <iterator>
std::vector<int> arr;
int n2,n1;
void reset(int n,int k){//Сбросить, всего элементв и пересекающихся
n1=n-k;
n2=n;
arr.resize(n*2-k);
for (int i=0;i<arr.size();i++)
arr[i]=i;
std::default_random_engine g(_rdtsc());
shuffle(arr.begin(),arr.end(),g);
}
void prn_a(){ //Начепятать в виде массивов
printf("\n1: ");
for (int i=0;i<n1;i++)
printf("%2d ",arr[i]);
printf("\n=: ");
for (int i=n1;i<n2;i++)
printf("%2d ",arr[i]);
printf("\n2: ");
for (int i=n2;i<arr.size();i++)
printf("%2d ",arr[i]);
}
double test_1(int k=3){//Стандартный std::set
uint64_t t=0;
uint64_t t1,t2;
std::set<int> c;
std::set<int> a(arr.data()+0,arr.data()+n2),b(arr.data()+n1,arr.data()+arr.size());
for (int o=0;o<k;o++){
//printf("\n1: ");
// for (auto i:a)
// printf("%2d ",i);
//printf("\n2: ");
//for (auto i:b)
// printf("%2d ",i);
c.clear();
t1=_rdtsc();
set_intersection(a.begin(),a.end(), b.begin(),b.end(), std::inserter(c,c.begin()));
t2=_rdtsc();
if (o) t+=(t2-t1);
if (c.size()!=n2-n1)
printf("\nerr in &");
// printf("\n&: ");
// for (auto i:c)
// printf("%2d ",i);
c.clear();
t1=_rdtsc();
set_union(a.begin(),a.end(), b.begin(),b.end(), std::inserter(c,c.begin()));
t2=_rdtsc();
if (o) t+=(t2-t1);
if (c.size()!=arr.size())
printf("\nerr in |");
//printf("\n|: ");
//for (auto i:c)
// printf("%2d ",i);
}
return double(t)/(k-1)*2.4e-6;
}
double test_3(int k=3){//Стандартный std::set
uint64_t t=0;
uint64_t t1,t2;
std::set<int> c;
std::set<int> a(arr.data()+0,arr.data()+n2),b(arr.data()+n1,arr.data()+arr.size());
for (int o=0;o<k;o++){
//printf("\n1: ");
// for (auto i:a)
// printf("%2d ",i);
//printf("\n2: ");
//for (auto i:b)
// printf("%2d ",i);
c.clear();
t1=_rdtsc();
{
std::vector<int> d;
set_intersection(a.begin(),a.end(), b.begin(),b.end(), std::back_inserter(d));
c.insert(d.begin(),d.end());}
t2=_rdtsc();
if (o) t+=(t2-t1);
if (c.size()!=n2-n1)
printf("\nerr in &");
// printf("\n&: ");
// for (auto i:c)
// printf("%2d ",i);
c.clear();
t1=_rdtsc();
{
std::vector<int> d;
set_union(a.begin(),a.end(), b.begin(),b.end(), std::back_inserter(d));
c.insert(d.begin(),d.end());
}
t2=_rdtsc();
if (o) t+=(t2-t1);
if (c.size()!=arr.size())
printf("\nerr in |");
//printf("\n|: ");
//for (auto i:c)
// printf("%2d ",i);
}
return double(t)/(k-1)*2.4e-6;
}
template<typename T>
struct my_tree{
struct node{
node *up;//Верхушка
node *le,*ri;//Ветки
T zn;
static node* __(T* a,T* b){
if (a==b)
return nullptr;
node* res=new node;
T* m=a+(b-a)/2;
res->zn=*m;
res->le=__(a,m);
res->ri=__(m+1,b);
if (res->le)
res->le->up=res;
if (res->ri)
res->ri->up=res;
return res;
}
node* next(){
node* h;
if (ri) {
h=ri;
while (h->le) h=h->le;
return h;
}else if (up){
h=up;
while (h and h->up and h->zn<zn)
h=h->up;
return (h->zn<zn)?nullptr:h;
}else return nullptr;
}
int size(){
return 1+(le?le->size():0)+(ri?ri->size():0);
}
void prn(){
if (le) {
// printf("(");
le->prn();
// printf(")");
}
node* ne=next();
printf("%d",zn);
// if (ne)
// printf("->%d",ne->zn);
printf(" ");
if (ri){
// printf("{");
ri->prn();
// printf("}");
}
}
};
node* core;
my_tree():core(nullptr){}
my_tree(T* i1,T* i2){
add(i1,i2);
}
void add(T* i1,T* i2){ //Я отсортирую, и потому дерево будет сбалансированное
core=nullptr;
std::vector<T> arr(i1,i2);
sort(arr.begin(),arr.end());
core=node::__(&*arr.begin(),&*arr.end());
core->up=nullptr;
}
node* begin(){
node* h=core;
while (h and h->le) h=h->le;
return h;
}
node* end(){
node* h=core;
while (h and h->ri) h=h->ri;
return h;
}
void clear(){
core=nullptr;//Освобождение памяти не нужно
}
int size(){ //Это же лишь тест
if (core)
return core->size();
else
return 0;
}
void prn(){
printf("\n[ ");
if (core)
core->prn();
printf("]");
}
void _intersection( my_tree<T>& a, my_tree<T>& b){
node *a1=a.begin();
node *a2=b.begin();
std::vector<T> c;
while (a1 and a2){
//++t;
// printf("\n a1: %2d a2: %2d",a1->zn,a2->zn);
if (a1->zn<a2->zn)
a1=a1->next();
else if (a1->zn>a2->zn)
a2=a2->next();
else {
c.push_back(a1->zn);
//printf(" %d ",a1->zn);
a1=a1->next();
a2=a2->next();
}
// if (t>10)break;
}
// printf("{");
// for (auto i:c)
// printf(" %d ",i);
// printf("}");
core=node::__(&*c.begin(),&*c.end());
core->up=nullptr;
}
void _union( my_tree<T>& a, my_tree<T>& b){
node *a1=a.begin();
node *a2=b.begin();
std::vector<T> c;
while (a1 and a2){
//++t;
// printf("\n a1: %2d a2: %2d",a1->zn,a2->zn);
if (a1->zn<a2->zn){
c.push_back(a1->zn);
a1=a1->next();}
else if (a1->zn>a2->zn){
c.push_back(a2->zn);
a2=a2->next();}
else {
c.push_back(a2->zn);
//printf(" %d ",a1->zn);
a1=a1->next();
a2=a2->next();
}
// if (t>10)break;
}
while (a1){
c.push_back(a1->zn);
a1=a1->next();
}
while (a2){
c.push_back(a2->zn);
a2=a2->next();
}
// printf("{");
// for (auto i:c)
// printf(" %d ",i);
// printf("}");
core=node::__(&*c.begin(),&*c.end());
core->up=nullptr;
}
};
double test_2(int k=3){
uint64_t t=0;
uint64_t t1,t2;
//
my_tree<int> c;
my_tree<int> a(arr.data()+0,arr.data()+n2),b(arr.data()+n1,arr.data()+arr.size());
//a.prn();
//b.prn();
for (int o=0;o<k;o++){
//printf("\n1: ");
// for (auto i:a)
// printf("%2d ",i);
//printf("\n2: ");
//for (auto i:b)
// printf("%2d ",i);
c.clear();
t1=_rdtsc();
c._intersection(a,b);
t2=_rdtsc();
//c.prn();
if (o) t+=(t2-t1);
if (c.size()!=n2-n1)
printf("\nerr in &");
// printf("\n&: ");
// for (auto i:c)
// printf("%2d ",i);
c.clear();
t1=_rdtsc();
c._union(a,b);
t2=_rdtsc();
//c.prn();
if (o) t+=(t2-t1);
if (c.size()!=arr.size())
printf("\nerr in |");
//printf("\n|: ");
//for (auto i:c)
// printf("%2d ",i);
}
return double(t)/(k-1)*2.4e-6;
}
void te(double (*fun)(int) ,int i){
reset(2*i,i);
double t=fun(2),s=1e3*t/i,s2=s/log(i)*4;
printf("\n%7d : %-12.3f n: %-5.2f nlog: %-5.2f", i,t,s,s2);
}
int main()
{
reset(6,2);
prn_a();
test_2(2);
printf("\n\n my_tree");
for (int i: {10, 31, 100, 316, 1000, 3162, 10000, 31622, 100000/*, 316227*/})
te(test_2,i);
printf("\n\n std::set");
for (int i: {10, 31, 100, 316, 1000, 3162, 10000, 31622, 100000/*, 316227*/})
te(test_1,i);
printf("\n\n std::set with vector");
for (int i: {10, 31, 100, 316, 1000, 3162, 10000, 31622, 100000/*, 316227*/})
te(test_3,i);
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dmVjdG9yPgojaW5jbHVkZSA8YWxnb3JpdGhtPgojaW5jbHVkZSA8cmFuZG9tPgojaW5jbHVkZSA8c2V0PgojaW5jbHVkZSA8eDg2aW50cmluLmg+CiNpbmNsdWRlIDxpdGVyYXRvcj4KCgoKc3RkOjp2ZWN0b3I8aW50PiBhcnI7CmludCBuMixuMTsKCnZvaWQgcmVzZXQoaW50IG4saW50IGspey8v0KHQsdGA0L7RgdC40YLRjCwg0LLRgdC10LPQviDRjdC70LXQvNC10L3RgtCyINC4INC/0LXRgNC10YHQtdC60LDRjtGJ0LjRhdGB0Y8KICAgbjE9bi1rOwogICBuMj1uOwogICBhcnIucmVzaXplKG4qMi1rKTsKICAgZm9yIChpbnQgaT0wO2k8YXJyLnNpemUoKTtpKyspCiAgICAgIGFycltpXT1pOwogICBzdGQ6OmRlZmF1bHRfcmFuZG9tX2VuZ2luZSAgZyhfcmR0c2MoKSk7CiAgIHNodWZmbGUoYXJyLmJlZ2luKCksYXJyLmVuZCgpLGcpOwp9Cgp2b2lkIHBybl9hKCl7ICAvL9Cd0LDRh9C10L/Rj9GC0LDRgtGMINCyINCy0LjQtNC1INC80LDRgdGB0LjQstC+0LIKICAgcHJpbnRmKCJcbjE6ICIpOwogICBmb3IgKGludCBpPTA7aTxuMTtpKyspCiAgICAgIHByaW50ZigiJTJkICIsYXJyW2ldKTsKICAgcHJpbnRmKCJcbj06ICIpOwogICBmb3IgKGludCBpPW4xO2k8bjI7aSsrKQogICAgICBwcmludGYoIiUyZCAiLGFycltpXSk7CiAgIHByaW50ZigiXG4yOiAiKTsKICAgZm9yIChpbnQgaT1uMjtpPGFyci5zaXplKCk7aSsrKQogICAgICBwcmludGYoIiUyZCAiLGFycltpXSk7Cgp9Cgpkb3VibGUgdGVzdF8xKGludCBrPTMpey8v0KHRgtCw0L3QtNCw0YDRgtC90YvQuSBzdGQ6OnNldAogICB1aW50NjRfdCB0PTA7CiAgIHVpbnQ2NF90IHQxLHQyOwogICBzdGQ6OnNldDxpbnQ+IGM7CiAgIHN0ZDo6c2V0PGludD4gYShhcnIuZGF0YSgpKzAsYXJyLmRhdGEoKStuMiksYihhcnIuZGF0YSgpK24xLGFyci5kYXRhKCkrYXJyLnNpemUoKSk7CiAgIGZvciAoaW50IG89MDtvPGs7bysrKXsKICAgICAgLy9wcmludGYoIlxuMTogIik7CiAgICAgIC8vIGZvciAoYXV0byBpOmEpCiAgICAgIC8vICAgIHByaW50ZigiJTJkICIsaSk7CiAgICAgIC8vcHJpbnRmKCJcbjI6ICIpOwogICAgICAvL2ZvciAoYXV0byBpOmIpCiAgICAgIC8vICAgcHJpbnRmKCIlMmQgIixpKTsKICAgICAgYy5jbGVhcigpOwogICAgICB0MT1fcmR0c2MoKTsKICAgICAgc2V0X2ludGVyc2VjdGlvbihhLmJlZ2luKCksYS5lbmQoKSwgYi5iZWdpbigpLGIuZW5kKCksIHN0ZDo6aW5zZXJ0ZXIoYyxjLmJlZ2luKCkpKTsKICAgICAgdDI9X3JkdHNjKCk7CiAgICAgIGlmIChvKSB0Kz0odDItdDEpOwogICAgICBpZiAoYy5zaXplKCkhPW4yLW4xKQogICAgICAgICBwcmludGYoIlxuZXJyIGluICYiKTsKCiAgICAgIC8vIHByaW50ZigiXG4mOiAiKTsKICAgICAgLy8gZm9yIChhdXRvIGk6YykKICAgICAgLy8gICBwcmludGYoIiUyZCAiLGkpOwogICAgICBjLmNsZWFyKCk7CiAgICAgIHQxPV9yZHRzYygpOwogICAgICBzZXRfdW5pb24oYS5iZWdpbigpLGEuZW5kKCksIGIuYmVnaW4oKSxiLmVuZCgpLCBzdGQ6Omluc2VydGVyKGMsYy5iZWdpbigpKSk7CiAgICAgIHQyPV9yZHRzYygpOwogICAgICBpZiAobykgdCs9KHQyLXQxKTsKICAgICAgaWYgKGMuc2l6ZSgpIT1hcnIuc2l6ZSgpKQogICAgICAgICBwcmludGYoIlxuZXJyIGluIHwiKTsKICAgICAgLy9wcmludGYoIlxufDogIik7CiAgICAgIC8vZm9yIChhdXRvIGk6YykKICAgICAgLy8gIHByaW50ZigiJTJkICIsaSk7CgogICB9CiAgIHJldHVybiBkb3VibGUodCkvKGstMSkqMi40ZS02Owp9CmRvdWJsZSB0ZXN0XzMoaW50IGs9Myl7Ly/QodGC0LDQvdC00LDRgNGC0L3Ri9C5IHN0ZDo6c2V0CiAgIHVpbnQ2NF90IHQ9MDsKICAgdWludDY0X3QgdDEsdDI7CiAgIHN0ZDo6c2V0PGludD4gYzsKICAgc3RkOjpzZXQ8aW50PiBhKGFyci5kYXRhKCkrMCxhcnIuZGF0YSgpK24yKSxiKGFyci5kYXRhKCkrbjEsYXJyLmRhdGEoKSthcnIuc2l6ZSgpKTsKICAgZm9yIChpbnQgbz0wO288aztvKyspewogICAgICAvL3ByaW50ZigiXG4xOiAiKTsKICAgICAgLy8gZm9yIChhdXRvIGk6YSkKICAgICAgLy8gICAgcHJpbnRmKCIlMmQgIixpKTsKICAgICAgLy9wcmludGYoIlxuMjogIik7CiAgICAgIC8vZm9yIChhdXRvIGk6YikKICAgICAgLy8gICBwcmludGYoIiUyZCAiLGkpOwogICAgICBjLmNsZWFyKCk7CiAgICAgIHQxPV9yZHRzYygpOwogICAgICB7CiAgICAgICAgIHN0ZDo6dmVjdG9yPGludD4gZDsKICAgICAgICAgc2V0X2ludGVyc2VjdGlvbihhLmJlZ2luKCksYS5lbmQoKSwgYi5iZWdpbigpLGIuZW5kKCksIHN0ZDo6YmFja19pbnNlcnRlcihkKSk7CiAgICAgICAgIGMuaW5zZXJ0KGQuYmVnaW4oKSxkLmVuZCgpKTt9CiAgICAgIHQyPV9yZHRzYygpOwogICAgICBpZiAobykgdCs9KHQyLXQxKTsKICAgICAgaWYgKGMuc2l6ZSgpIT1uMi1uMSkKICAgICAgICAgcHJpbnRmKCJcbmVyciBpbiAmIik7CgogICAgICAvLyBwcmludGYoIlxuJjogIik7CiAgICAgIC8vIGZvciAoYXV0byBpOmMpCiAgICAgIC8vICAgcHJpbnRmKCIlMmQgIixpKTsKICAgICAgYy5jbGVhcigpOwogICAgICB0MT1fcmR0c2MoKTsKICAgICAgewogICAgICAgICBzdGQ6OnZlY3RvcjxpbnQ+IGQ7CiAgICAgICAgIHNldF91bmlvbihhLmJlZ2luKCksYS5lbmQoKSwgYi5iZWdpbigpLGIuZW5kKCksIHN0ZDo6YmFja19pbnNlcnRlcihkKSk7CiAgICAgICAgIGMuaW5zZXJ0KGQuYmVnaW4oKSxkLmVuZCgpKTsKICAgICAgfQogICAgICB0Mj1fcmR0c2MoKTsKICAgICAgaWYgKG8pIHQrPSh0Mi10MSk7CiAgICAgIGlmIChjLnNpemUoKSE9YXJyLnNpemUoKSkKICAgICAgICAgcHJpbnRmKCJcbmVyciBpbiB8Iik7CiAgICAgIC8vcHJpbnRmKCJcbnw6ICIpOwogICAgICAvL2ZvciAoYXV0byBpOmMpCiAgICAgIC8vICBwcmludGYoIiUyZCAiLGkpOwoKICAgfQogICByZXR1cm4gZG91YmxlKHQpLyhrLTEpKjIuNGUtNjsKfQoKCnRlbXBsYXRlPHR5cGVuYW1lIFQ+CnN0cnVjdCBteV90cmVlewogICBzdHJ1Y3Qgbm9kZXsKICAgICAgbm9kZSAqdXA7Ly/QktC10YDRhdGD0YjQutCwCiAgICAgIG5vZGUgKmxlLCpyaTsvL9CS0LXRgtC60LgKICAgICAgVCB6bjsKICAgICAgc3RhdGljIG5vZGUqIF9fKFQqIGEsVCogYil7CiAgICAgICAgIGlmIChhPT1iKQogICAgICAgICAgICByZXR1cm4gbnVsbHB0cjsKICAgICAgICAgbm9kZSogcmVzPW5ldyBub2RlOwogICAgICAgICBUKiBtPWErKGItYSkvMjsKICAgICAgICAgcmVzLT56bj0qbTsKICAgICAgICAgcmVzLT5sZT1fXyhhLG0pOwogICAgICAgICByZXMtPnJpPV9fKG0rMSxiKTsKICAgICAgICAgaWYgKHJlcy0+bGUpCiAgICAgICAgICAgIHJlcy0+bGUtPnVwPXJlczsKICAgICAgICAgaWYgKHJlcy0+cmkpCiAgICAgICAgICAgIHJlcy0+cmktPnVwPXJlczsKICAgICAgICAgcmV0dXJuIHJlczsKICAgICAgfQogICAgICBub2RlKiBuZXh0KCl7CiAgICAgICAgIG5vZGUqIGg7CiAgICAgICAgIGlmIChyaSkgewogICAgICAgICAgICBoPXJpOwogICAgICAgICAgICB3aGlsZSAoaC0+bGUpIGg9aC0+bGU7CiAgICAgICAgICAgIHJldHVybiBoOwogICAgICAgICB9ZWxzZSBpZiAodXApewogICAgICAgICAgICBoPXVwOwogICAgICAgICAgICB3aGlsZSAoaCBhbmQgaC0+dXAgYW5kIGgtPnpuPHpuKQogICAgICAgICAgICAgICBoPWgtPnVwOwogICAgICAgICAgICByZXR1cm4gKGgtPnpuPHpuKT9udWxscHRyOmg7CiAgICAgICAgIH1lbHNlIHJldHVybiBudWxscHRyOwogICAgICB9CgogICAgICBpbnQgc2l6ZSgpewogICAgICAgICByZXR1cm4gMSsobGU/bGUtPnNpemUoKTowKSsocmk/cmktPnNpemUoKTowKTsKICAgICAgfQogICAgICB2b2lkIHBybigpewogICAgICAgICBpZiAobGUpIHsKICAgICAgICAgICAgLy8gICAgICAgICAgICBwcmludGYoIigiKTsKICAgICAgICAgICAgbGUtPnBybigpOwogICAgICAgICAgICAvLyAgICAgICAgICAgIHByaW50ZigiKSIpOwogICAgICAgICB9CiAgICAgICAgIG5vZGUqIG5lPW5leHQoKTsKICAgICAgICAgcHJpbnRmKCIlZCIsem4pOwogICAgICAgICAvLyBpZiAobmUpCiAgICAgICAgIC8vICAgIHByaW50ZigiLT4lZCIsbmUtPnpuKTsKICAgICAgICAgcHJpbnRmKCIgIik7CiAgICAgICAgIGlmIChyaSl7CiAgICAgICAgICAgIC8vICAgICAgICAgICAgcHJpbnRmKCJ7Iik7CiAgICAgICAgICAgIHJpLT5wcm4oKTsKICAgICAgICAgICAgLy8gICAgICAgICAgICBwcmludGYoIn0iKTsKICAgICAgICAgfQogICAgICB9CiAgIH07CiAgIG5vZGUqIGNvcmU7CgogICBteV90cmVlKCk6Y29yZShudWxscHRyKXt9CiAgIG15X3RyZWUoVCogaTEsVCogaTIpewogICAgICBhZGQoaTEsaTIpOwogICB9CiAgIHZvaWQgYWRkKFQqIGkxLFQqIGkyKXsgLy/QryDQvtGC0YHQvtGA0YLQuNGA0YPRjiwg0Lgg0L/QvtGC0L7QvNGDINC00LXRgNC10LLQviDQsdGD0LTQtdGCINGB0LHQsNC70LDQvdGB0LjRgNC+0LLQsNC90L3QvtC1CiAgICAgIGNvcmU9bnVsbHB0cjsKICAgICAgc3RkOjp2ZWN0b3I8VD4gYXJyKGkxLGkyKTsKICAgICAgc29ydChhcnIuYmVnaW4oKSxhcnIuZW5kKCkpOwogICAgICBjb3JlPW5vZGU6Ol9fKCYqYXJyLmJlZ2luKCksJiphcnIuZW5kKCkpOwogICAgICBjb3JlLT51cD1udWxscHRyOwogICB9CiAgIG5vZGUqIGJlZ2luKCl7CiAgICAgIG5vZGUqIGg9Y29yZTsKICAgICAgd2hpbGUgKGggYW5kIGgtPmxlKSBoPWgtPmxlOwogICAgICByZXR1cm4gaDsKICAgfQogICBub2RlKiBlbmQoKXsKICAgICAgbm9kZSogaD1jb3JlOwogICAgICB3aGlsZSAoaCBhbmQgaC0+cmkpIGg9aC0+cmk7CiAgICAgIHJldHVybiBoOwogICB9CiAgIHZvaWQgY2xlYXIoKXsKICAgICAgY29yZT1udWxscHRyOy8v0J7RgdCy0L7QsdC+0LbQtNC10L3QuNC1INC/0LDQvNGP0YLQuCDQvdC1INC90YPQttC90L4KICAgfQogICBpbnQgc2l6ZSgpeyAvL9Ct0YLQviDQttC1INC70LjRiNGMINGC0LXRgdGCCiAgICAgIGlmIChjb3JlKQogICAgICAgICByZXR1cm4gY29yZS0+c2l6ZSgpOwogICAgICBlbHNlCiAgICAgICAgIHJldHVybiAwOwogICB9CiAgIHZvaWQgcHJuKCl7CiAgICAgIHByaW50ZigiXG5bICIpOwogICAgICBpZiAoY29yZSkKICAgICAgICAgY29yZS0+cHJuKCk7CiAgICAgIHByaW50ZigiXSIpOwogICB9CiAgIHZvaWQgX2ludGVyc2VjdGlvbiggbXlfdHJlZTxUPiYgYSwgbXlfdHJlZTxUPiYgYil7CiAgICAgIG5vZGUgKmExPWEuYmVnaW4oKTsKICAgICAgbm9kZSAqYTI9Yi5iZWdpbigpOwogICAgICBzdGQ6OnZlY3RvcjxUPiBjOwogICAgICB3aGlsZSAoYTEgYW5kIGEyKXsKICAgICAgICAgLy8rK3Q7CiAgICAgICAgIC8vIHByaW50ZigiXG4gYTE6ICUyZCAgYTI6ICUyZCIsYTEtPnpuLGEyLT56bik7CiAgICAgICAgIGlmIChhMS0+em48YTItPnpuKQogICAgICAgICAgICBhMT1hMS0+bmV4dCgpOwogICAgICAgICBlbHNlIGlmIChhMS0+em4+YTItPnpuKQogICAgICAgICAgICBhMj1hMi0+bmV4dCgpOwogICAgICAgICBlbHNlIHsKICAgICAgICAgICAgYy5wdXNoX2JhY2soYTEtPnpuKTsKICAgICAgICAgICAgLy9wcmludGYoIiAlZCAiLGExLT56bik7CiAgICAgICAgICAgIGExPWExLT5uZXh0KCk7CiAgICAgICAgICAgIGEyPWEyLT5uZXh0KCk7CiAgICAgICAgIH0KCiAgICAgICAgIC8vIGlmICh0PjEwKWJyZWFrOwoKICAgICAgfQogICAgICAvLyAgICAgIHByaW50ZigieyIpOwogICAgICAvLyAgICAgIGZvciAoYXV0byBpOmMpCiAgICAgIC8vICAgICAgICAgcHJpbnRmKCIgJWQgIixpKTsKICAgICAgLy8gICAgICBwcmludGYoIn0iKTsKICAgICAgY29yZT1ub2RlOjpfXygmKmMuYmVnaW4oKSwmKmMuZW5kKCkpOwogICAgICBjb3JlLT51cD1udWxscHRyOwoKICAgfQogICB2b2lkIF91bmlvbiggbXlfdHJlZTxUPiYgYSwgbXlfdHJlZTxUPiYgYil7CiAgICAgIG5vZGUgKmExPWEuYmVnaW4oKTsKICAgICAgbm9kZSAqYTI9Yi5iZWdpbigpOwogICAgICBzdGQ6OnZlY3RvcjxUPiBjOwogICAgICB3aGlsZSAoYTEgYW5kIGEyKXsKICAgICAgICAgLy8rK3Q7CiAgICAgICAgIC8vIHByaW50ZigiXG4gYTE6ICUyZCAgYTI6ICUyZCIsYTEtPnpuLGEyLT56bik7CiAgICAgICAgIGlmIChhMS0+em48YTItPnpuKXsKICAgICAgICAgICAgYy5wdXNoX2JhY2soYTEtPnpuKTsKICAgICAgICAgICAgYTE9YTEtPm5leHQoKTt9CiAgICAgICAgIGVsc2UgaWYgKGExLT56bj5hMi0+em4pewogICAgICAgICAgICBjLnB1c2hfYmFjayhhMi0+em4pOwogICAgICAgICAgICBhMj1hMi0+bmV4dCgpO30KICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgIGMucHVzaF9iYWNrKGEyLT56bik7CiAgICAgICAgICAgIC8vcHJpbnRmKCIgJWQgIixhMS0+em4pOwogICAgICAgICAgICBhMT1hMS0+bmV4dCgpOwogICAgICAgICAgICBhMj1hMi0+bmV4dCgpOwogICAgICAgICB9CgogICAgICAgICAvLyBpZiAodD4xMClicmVhazsKCiAgICAgIH0KICAgICAgd2hpbGUgKGExKXsKICAgICAgICAgYy5wdXNoX2JhY2soYTEtPnpuKTsKICAgICAgICAgYTE9YTEtPm5leHQoKTsKICAgICAgfQogICAgICB3aGlsZSAoYTIpewogICAgICAgICBjLnB1c2hfYmFjayhhMi0+em4pOwogICAgICAgICBhMj1hMi0+bmV4dCgpOwogICAgICB9CiAgICAgIC8vICAgICAgcHJpbnRmKCJ7Iik7CiAgICAgIC8vICAgICAgZm9yIChhdXRvIGk6YykKICAgICAgLy8gICAgICAgICBwcmludGYoIiAlZCAiLGkpOwogICAgICAvLyAgICAgIHByaW50ZigifSIpOwogICAgICBjb3JlPW5vZGU6Ol9fKCYqYy5iZWdpbigpLCYqYy5lbmQoKSk7CiAgICAgIGNvcmUtPnVwPW51bGxwdHI7CgogICB9Cn07Cgpkb3VibGUgdGVzdF8yKGludCBrPTMpewogICB1aW50NjRfdCB0PTA7CiAgIHVpbnQ2NF90IHQxLHQyOwogICAvLwogICBteV90cmVlPGludD4gYzsKICAgbXlfdHJlZTxpbnQ+IGEoYXJyLmRhdGEoKSswLGFyci5kYXRhKCkrbjIpLGIoYXJyLmRhdGEoKStuMSxhcnIuZGF0YSgpK2Fyci5zaXplKCkpOwogICAvL2EucHJuKCk7CiAgIC8vYi5wcm4oKTsKICAgZm9yIChpbnQgbz0wO288aztvKyspewogICAgICAvL3ByaW50ZigiXG4xOiAiKTsKICAgICAgLy8gZm9yIChhdXRvIGk6YSkKICAgICAgLy8gICAgcHJpbnRmKCIlMmQgIixpKTsKICAgICAgLy9wcmludGYoIlxuMjogIik7CiAgICAgIC8vZm9yIChhdXRvIGk6YikKICAgICAgLy8gICBwcmludGYoIiUyZCAiLGkpOwogICAgICBjLmNsZWFyKCk7CiAgICAgIHQxPV9yZHRzYygpOwogICAgICBjLl9pbnRlcnNlY3Rpb24oYSxiKTsKICAgICAgdDI9X3JkdHNjKCk7CiAgICAgIC8vYy5wcm4oKTsKICAgICAgaWYgKG8pIHQrPSh0Mi10MSk7CiAgICAgIGlmIChjLnNpemUoKSE9bjItbjEpCiAgICAgICAgIHByaW50ZigiXG5lcnIgaW4gJiIpOwoKICAgICAgLy8gcHJpbnRmKCJcbiY6ICIpOwogICAgICAvLyBmb3IgKGF1dG8gaTpjKQogICAgICAvLyAgIHByaW50ZigiJTJkICIsaSk7CiAgICAgIGMuY2xlYXIoKTsKICAgICAgdDE9X3JkdHNjKCk7CiAgICAgIGMuX3VuaW9uKGEsYik7CiAgICAgIHQyPV9yZHRzYygpOwogICAgICAvL2MucHJuKCk7CiAgICAgIGlmIChvKSB0Kz0odDItdDEpOwogICAgICBpZiAoYy5zaXplKCkhPWFyci5zaXplKCkpCiAgICAgICAgIHByaW50ZigiXG5lcnIgaW4gfCIpOwogICAgICAvL3ByaW50ZigiXG58OiAiKTsKICAgICAgLy9mb3IgKGF1dG8gaTpjKQogICAgICAvLyAgcHJpbnRmKCIlMmQgIixpKTsKCiAgIH0KICAgcmV0dXJuIGRvdWJsZSh0KS8oay0xKSoyLjRlLTY7Cn0KCnZvaWQgdGUoZG91YmxlICgqZnVuKShpbnQpICxpbnQgaSl7CgogICByZXNldCgyKmksaSk7CiAgIGRvdWJsZSB0PWZ1bigyKSxzPTFlMyp0L2ksczI9cy9sb2coaSkqNDsKICAgcHJpbnRmKCJcbiU3ZCA6ICUtMTIuM2YgbjogJS01LjJmICAgbmxvZzogJS01LjJmIiwgaSx0LHMsczIpOwp9CgppbnQgbWFpbigpCnsKICAgcmVzZXQoNiwyKTsKICAgcHJuX2EoKTsKICAgdGVzdF8yKDIpOwoKICAgcHJpbnRmKCJcblxuIG15X3RyZWUiKTsKICAgZm9yIChpbnQgaTogezEwLCAzMSwgMTAwLCAzMTYsIDEwMDAsIDMxNjIsIDEwMDAwLCAzMTYyMiwgMTAwMDAwLyosIDMxNjIyNyovfSkKICAgICAgdGUodGVzdF8yLGkpOwogICBwcmludGYoIlxuXG4gc3RkOjpzZXQiKTsKICAgZm9yIChpbnQgaTogezEwLCAzMSwgMTAwLCAzMTYsIDEwMDAsIDMxNjIsIDEwMDAwLCAzMTYyMiwgMTAwMDAwLyosIDMxNjIyNyovfSkKICAgICAgdGUodGVzdF8xLGkpOwogICBwcmludGYoIlxuXG4gc3RkOjpzZXQgd2l0aCB2ZWN0b3IiKTsKICAgZm9yIChpbnQgaTogezEwLCAzMSwgMTAwLCAzMTYsIDEwMDAsIDMxNjIsIDEwMDAwLCAzMTYyMiwgMTAwMDAwLyosIDMxNjIyNyovfSkKICAgICAgdGUodGVzdF8zLGkpOwoKCn0K