├── Bfs ├── README.md └── source.cpp ├── Bignum ├── README.md └── source.cpp ├── Centroid Decomposition └── source.cpp ├── Dfs ├── README.md ├── source.cpp └── source2.cpp ├── Dijkstra ├── README.md ├── source.cpp └── source2.cpp ├── Dinic └── source.cpp ├── EdmondsKarp └── source.cpp ├── Hash table ├── README.md └── source.c ├── Heavy Ligt Decomposition └── source.cpp ├── Kruskal ├── README.md └── source.cpp ├── Li_Chao_Tree └── source.cpp ├── Lowest Common Ancestor ├── source.cpp └── source2.cpp ├── Merge heap ├── README.md └── source.cpp ├── Min-Cost Max-Flow └── source.cpp ├── Monotone chain ├── README.md └── source.cpp ├── Prim ├── README.md └── source.cpp ├── Quicksort ├── README.md └── source.cpp ├── README.md ├── Treap ├── README.md ├── source.cpp └── source2.cpp └── Virtual Tree └── source.cpp /Bfs/README.md: -------------------------------------------------------------------------------- 1 | # Breadth First Search - Αναζήτηση κατά πλάτος 2 | 3 | Η αναζήτηση κατά πλάτος είναι μια αναζήτηση σε γράφο η οποία επισκέπτεται πρώτα τους κοντινότερους κόμβους στην πηγή της αναζήτησης, και αργότερα τους μακρυνότερους. Επομένως, όταν πρωτοφτάνει η bfs σε έναν κόμβο ενός **αβαρούς γράφου**, τον έχει συναντήσει με την ελάχιστη απόσταση. Η πολυπλοκότητα του αλγορίθμου αυτού είναι *O(n+m)*, όπου n το πλήθος των κορυφών, και m το πλήθος των ακμών. 4 | 5 | ## Περιγραφή του αλγορίθμου 6 | 7 | Ο αλγόριθμος δέχεται ως είσοδο την περιγραφή του γράφου (ως μια σειρά από ακμές) και μια αρχική κορυφή. Στην αρχή, τωρινή κορυφή τίθεται η αρχική κορυφή. Σε κάθε βήμα του αλγορίθμου, εξετάζονται οι γείτονες της τωρινής κορυφής. Όσοι γείτονες δεν έχουν ακόμα ελεγχθεί από τον αλγόριθμο, προστίθενται στο τέλος της ουράς. Μετά από αυτό, τωρινή κορυφή γίνεται η ακμή στην αρχή της ουράς, και αφαιρείται από την ουρά. 8 | 9 | Στην υλοποίηση του αλγορίθμου που παρατίθεται εδώ, η επιστροφή του αλγορίθμου είναι θετική εάν υπάρχει μονοπάτι από την πηγή σε όλες τις κορυφές, αλλιώς είναι αρνητική. 10 | -------------------------------------------------------------------------------- /Bfs/source.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | #define MAXN 1000000 //Το μέγιστο πλήθος κορυφών 8 | 9 | int N, M; //Το πλήθος των κορυφών και το πλήθος των ακμών 10 | bool vis[MAXN+5]; //Ο πίνακας που υποδεικνύει ποιους κόμβους έχει επισκεφτεί ο αλγόριθμος 11 | vector adj[MAXN+5]; //Η λίστα γειτνίασης 12 | 13 | void Bfs(int source) { 14 | queue qu; 15 | qu.push(source); 16 | int now; 17 | 18 | while(!qu.empty()) { 19 | now=qu.front(); 20 | qu.pop(); 21 | vis[now]=true; 22 | 23 | for(int i=0; i // scanf, printf 2 | #include // strlen, memset 3 | 4 | #define llint long long 5 | #define MAXDIG 16 6 | #define POWR 9 7 | #define BASE 1000000000 //= 10^POWR = 10^9 8 | 9 | struct bignum { //Ο μέγιστος αριθμός είναι 10^(POWR*MAXDIG)-1 = 10^144-1 10 | int d[MAXDIG]; // Ο πίνακας αυτός αποτελείται από sizeof(int)*MAXDIG = 4*16 = 64 bytes 11 | 12 | void print() { // Τυπώνει τον αριθμό 13 | bool started=false; 14 | for(int i=MAXDIG-1; i>=0; --i) { 15 | if(!started && d[i]==0) { 16 | continue; 17 | } 18 | if(!started) { 19 | started=true; 20 | printf("%d", d[i]); 21 | } 22 | else { 23 | if(d[i]<0) { 24 | printf("%.9d", -d[i]); 25 | } 26 | else { 27 | printf("%.9d", d[i]); 28 | } 29 | } 30 | } 31 | if(!started) { 32 | printf("0"); 33 | } 34 | } 35 | 36 | void to_bignum(char *str) { // Μετατρέπει το str σε bignum. Το str είναι βάση 10, και το most significant bit είναι το δεξιότερο 37 | int S, powr[POWR]; 38 | powr[0]=1; 39 | if(str[0]=='-') { 40 | powr[0]=-1; 41 | ++str; 42 | } 43 | S=strlen(str); 44 | for(int i=1; i=0; --i) { 73 | if(u.d[i]==v.d[i]) { 74 | continue; 75 | } 76 | return u.d[i]=BASE) { 89 | carry=1; 90 | } 91 | else if(out.d[i]<0) { 92 | carry=-1; 93 | } 94 | out.d[i]-=carry*BASE; 95 | } 96 | return out; 97 | } 98 | 99 | bignum add(bignum u, bignum v) { // Επιστρέφει το άθροισμα u+v 100 | if(comp(abs(u), abs(v))) { 101 | return add(v, u); 102 | } 103 | if(comp(u, ZERO)) { 104 | return neg(add_unsigned(neg(u),neg(v))); 105 | } 106 | return add_unsigned(u,v); 107 | } 108 | 109 | bignum subtract(bignum u, bignum v) { // Επιστρέφει τη διαφορά u-v 110 | return add(u,neg(v)); 111 | } 112 | 113 | bignum mult(bignum u, bignum v) { // Επιστρέφει το γινόμενο u*v 114 | if(comp(ZERO, u) != comp(ZERO, v)) { 115 | return neg(mult(abs(u), abs(v))); 116 | } 117 | bignum out; 118 | llint carry=0, tmp; 119 | memset(&out, 0, sizeof(out)); 120 | 121 | for(int i=0; i 6 | 7 | using namespace std; 8 | 9 | const int MAX_N = ; // <- insert value 10 | 11 | vector gr[MAX_N]; // adjacency list of the tree 12 | vector tree[MAX_N]; // centroid tree 13 | bool mark[MAX_N]; // currently marked centroids 14 | int sz[MAX_N]; // subtree size 15 | 16 | void get_sz(int u, int p) { 17 | sz[u] = 1; 18 | for (auto v : gr[u]) { 19 | if (v == p || mark[v]) continue; 20 | get_sz(v, u); 21 | sz[u] += sz[v]; 22 | } 23 | } 24 | 25 | int cent_dec(int u, int p, const int n) { 26 | int big = -1, mx = -1; 27 | for (auto v : gr[u]) { 28 | if (!mark[v] && v != p && sz[v] > mx) { 29 | mx = sz[v]; 30 | big = v; 31 | } 32 | } 33 | if (2 * mx <= n) { 34 | mark[u] = true; 35 | for (auto v : gr[u]) { 36 | if (mark[v]) continue; 37 | get_sz(v, u); 38 | int cent = cent_dec(v, u, sz[v]); 39 | tree[u].push_back(cent); 40 | } 41 | return u; 42 | } else { 43 | return cent_dec(big, u, n); 44 | } 45 | } 46 | 47 | /* 48 | int main() { 49 | get_sz(1, -1); 50 | int centroid = cent_dec(1, -1, sz[1]); 51 | return 0; 52 | } 53 | */ 54 | 55 | -------------------------------------------------------------------------------- /Dfs/README.md: -------------------------------------------------------------------------------- 1 | # Depth First Search - Αναζήτηση κατά βάθος 2 | 3 | Η αναζήτηση κατά βάθος είναι μια αναζήτηση γράφου η οποία επισκέπτεται τους κόμβους του γράφου ακολουθώντας κάθε φορά το μεγαλύτερο μονοπάτι που μπορεί να ακολουθήσει, ξεκινώτας από την πηγή, και γυρνώντας πίσω όταν δεν μπορεί πλέον να προχωρήσει. Η πολυπλοκότητα του αλγορίθμου είναι *O(n+m)*, όπου n το πλήθος των κορυφών και m το πλήθος των ακμών του γράφου. 4 | 5 | ## Περιγραφή του αλγορίθμου 6 | 7 | Ο αλγόριθμος δέχεται ως είσοδο την περιγραφή του γράφου (ως μια σειρά από ακμές) και μια αρχική κορυφή. Στην αρχή, τωρινή κορυφή τίθεται η πηγή. Σε κάθε βήμα του αλγορίθμου, όσους γείτονες της τωρινής κορυφής δεν έχει ακόμη επισκεφτεί ο αλγόριθμος, τις προσθέτει σε μία στοίβα. Στο επόμενο βήμα, τωρινή κορυφή κάνει το πρώτο στοιχείο της στοίβας και το αφαιρεί από αυτήν. 8 | 9 | Στη δεύτερη υλοποίηση, η dfs είναι κάπως διαφορετική. Αναδρομικά, ο αλγόριθμος επισκέπτεται από την τωρινή κορυφή, τον πρώτο γείτονα που δεν έχει ακόμα επισκεφτεί. Όταν φτάνει σε κατάσταση που δεν μπορεί να προχωρήσει σε επόμενο γείτονα, η συνάρτηση επιστρέφει, και αυτή που την κάλεσε συνεχίζει στον επόμενο γείτονα που δεν έχει επισκεφτεί. 10 | 11 | Στις υλοποιήσεις που παρατίθενται εδώ, η επιστροφή του αλγορίθμου είναι θετική εάν υπάρχει μονοπάτι από την πηγή σε όλες τις κορυφές, αλλιώς είναι αρνητική. 12 | -------------------------------------------------------------------------------- /Dfs/source.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | #define MAXN 1000000 //Το μέγιστο πλήθος κορυφών 8 | 9 | int N, M; //Το πλήθος των κορυφών και το πλήθος των ακμών 10 | bool vis[MAXN+5]; //Ο πίνακας που υποδεικνύει ποιους κόμβους έχει επισκεφτεί ο αλγόριθμος 11 | vector adj[MAXN+5]; //Η λίστα γειτνίασης 12 | 13 | void Dfs(int source) { 14 | stack st; 15 | st.push(source); 16 | int now; 17 | 18 | while(!st.empty()) { 19 | now=st.top(); 20 | st.pop(); 21 | vis[now]=true; 22 | 23 | for(int i=0; i 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | #define MAXN 1000000 //Το μέγιστο πλήθος κορυφών 8 | 9 | int N, M; //Το πλήθος των κορυφών και το πλήθος των ακμών 10 | bool vis[MAXN+5]; //Ο πίνακας που υποδεικνύει ποιους κόμβους έχει επισκεφτεί ο αλγόριθμος 11 | vector adj[MAXN+5]; //Η λίστα γειτνίασης 12 | 13 | void Dfs(int now) { 14 | vis[now]=true; 15 | for(int i=0; i // printf, scanf 2 | #include // pair 3 | #include // vector 4 | #include // set 5 | 6 | using namespace std; 7 | 8 | #define mp make_pair 9 | #define pb push_back 10 | #define X first 11 | #define Y second 12 | #define MAXN 100000 13 | 14 | int N, M, S, D; 15 | bool vis[MAXN]; 16 | vector adj[MAXN], dist[MAXN]; 17 | 18 | int Dijkstra() { 19 | pair now; 20 | set > pq; 21 | pq.insert(mp(0, S)); 22 | 23 | while(!pq.empty()) { 24 | now=*pq.begin(); 25 | pq.erase(pq.begin()); 26 | 27 | if(now.Y==D) { 28 | return now.X; 29 | } 30 | 31 | if(vis[now.Y]) { 32 | continue; 33 | } 34 | vis[now.Y]=true; 35 | 36 | for(size_t i=0; i // printf, scanf 2 | #include // pair 3 | #include // priority_queue 4 | 5 | using namespace std; 6 | 7 | #define mp make_pair 8 | #define pb push_back 9 | #define X first 10 | #define Y second 11 | #define MAXN 100000 12 | 13 | struct el { 14 | el* next; 15 | int to, val; 16 | el(el* next, int to, int val) { 17 | this->next=next; 18 | this->to=to; 19 | this->val=val; 20 | } 21 | } *adj[MAXN]; 22 | 23 | int N, M, S, D; 24 | bool vis[MAXN]; 25 | 26 | int Dijkstra() { 27 | pair now; 28 | priority_queue > pq; 29 | pq.push(mp(0, S)); 30 | 31 | while(!pq.empty()) { 32 | now=pq.top(); 33 | pq.pop(); 34 | 35 | if(now.Y==D) { 36 | return now.X; 37 | } 38 | 39 | if(vis[now.Y]) { 40 | continue; 41 | } 42 | 43 | vis[now.Y]=true; 44 | 45 | for(el* nxt=adj[now.Y]; nxt; nxt=nxt->next) { 46 | if(!vis[nxt->to]) { 47 | pq.push(mp(now.X+nxt->val, nxt->to)); 48 | } 49 | } 50 | } 51 | 52 | return -1; 53 | } 54 | 55 | int main() { 56 | int from, to, val; 57 | scanf("%d %d %d %d", &N, &M, &S, &D); 58 | for(int i=1; i<=M; ++i) { 59 | scanf("%d %d %d", &from, &to, &val); 60 | adj[from]=new el(adj[from], to, val); 61 | } 62 | 63 | int ans=Dijkstra(); 64 | if(ans==-1) { 65 | printf("Cannot reach destination\n"); 66 | } 67 | else { 68 | printf("%d\n", ans); 69 | } 70 | 71 | return 0; 72 | } 73 | 74 | -------------------------------------------------------------------------------- /Dinic/source.cpp: -------------------------------------------------------------------------------- 1 | #include // fill, min 2 | #include // memset 3 | #include 4 | #include // numeric_limits 5 | #include 6 | 7 | using namespace std; 8 | 9 | // Only need to specify NODES, EDGES 10 | 11 | template 12 | struct Dinic { 13 | static const int NODES; 14 | static const int EDGES; 15 | static const T INF = numeric_limits::max(); 16 | 17 | vector adj[NODES]; 18 | int level[NODES], st[NODES]; 19 | int to[EDGES], ed_cnt; 20 | T cap[EDGES]; 21 | 22 | void init() { 23 | fill(adj, adj + NODES, vector()); 24 | ed_cnt = 0; 25 | } 26 | 27 | void addEdge(int u, int v, T c) { 28 | adj[u].push_back(ed_cnt); 29 | to[ed_cnt] = v; 30 | cap[ed_cnt] = c; 31 | ed_cnt++; 32 | 33 | adj[v].push_back(ed_cnt); 34 | to[ed_cnt] = u; 35 | cap[ed_cnt] = 0; 36 | ed_cnt++; 37 | } 38 | 39 | bool bfs(int s, int t) { 40 | memset(level, -1, sizeof level); 41 | queue q; 42 | 43 | level[s] = 0; 44 | q.push(s); 45 | 46 | while (!q.empty()) { 47 | int u = q.front(); 48 | q.pop(); 49 | 50 | if (u == t) break; 51 | 52 | for (auto e : adj[u]) { 53 | int v = to[e]; 54 | if (cap[e] > ( T )0 && level[v] == -1) { 55 | level[v] = level[u] + 1; 56 | q.push(v); 57 | } 58 | } 59 | } 60 | 61 | return level[t] != -1; 62 | } 63 | 64 | T dfs(int u, const int t, T f) { 65 | if (u == t) return f; 66 | for (; st[u] < (int)adj[u].size(); st[u]++) { 67 | int e = adj[u][st[u]]; 68 | int v = to[e]; 69 | if (cap[e] <= ( T )0 || level[v] != level[u] + 1) 70 | continue; 71 | T ret = dfs(v, t, min(f, cap[e])); 72 | if (ret != ( T )0) { 73 | cap[e] -= ret; 74 | cap[e ^ 1] += ret; 75 | return ret; 76 | } 77 | } 78 | return ( T )0; 79 | } 80 | 81 | T maxflow(int s, int t) { 82 | T mf = 0; 83 | while (bfs(s, t)) { 84 | memset(st, 0, sizeof st); 85 | T f; 86 | while ((f = dfs(s, t, INF)) != ( T )0) { 87 | mf += f; 88 | } 89 | } 90 | return mf; 91 | } 92 | }; 93 | 94 | -------------------------------------------------------------------------------- /EdmondsKarp/source.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Edmonds-Karp Max Flow Algorithm. Works in O(V * E ^ 2) worst case. 3 | This implementation only supports one edge per node-pair in the residual network. 4 | */ 5 | #include // fill, min 6 | #include // memset 7 | #include 8 | #include // numeric_limits 9 | #include 10 | 11 | using namespace std; 12 | 13 | // T is the capacity datatype 14 | template 15 | struct EdmondsKarp { 16 | static const int NODES = ; // <- insert value 17 | static const T INF = numeric_limits::max(); 18 | 19 | T cap[NODES][NODES]; 20 | vector adj[NODES]; 21 | int p[NODES]; 22 | 23 | void init() { 24 | fill(adj, adj + NODES, vector()); 25 | } 26 | 27 | void addEdge(int u, int v, T c) { 28 | adj[u].push_back(v); 29 | cap[u][v] = c; 30 | 31 | adj[v].push_back(u); 32 | cap[v][u] = 0; 33 | } 34 | 35 | bool bfs(int s, int t) { 36 | memset(p, -1, sizeof p); 37 | bitset visit; 38 | queue q; 39 | 40 | visit[s] = true; 41 | q.push(s); 42 | 43 | while (!q.empty()) { 44 | int u = q.front(); 45 | q.pop(); 46 | 47 | for (auto v : adj[u]) { 48 | if (!visit[v] && cap[u][v] > ( T )0) { 49 | p[v] = u; 50 | visit[v] = true; 51 | q.push(v); 52 | } 53 | } 54 | } 55 | 56 | return visit[t]; 57 | } 58 | 59 | T maxflow(int s, int t) { 60 | T mf = 0; 61 | while (bfs(s, t)) { 62 | T f = INF; 63 | for (int u = t; u != s; u = p[u]) 64 | f = min(f, cap[p[u]][u]); 65 | if (f == ( T )0) 66 | break; 67 | for (int u = t; u != s; u = p[u]) { 68 | cap[p[u]][u] -= f; 69 | cap[u][p[u]] += f; 70 | } 71 | mf += f; 72 | } 73 | return mf; 74 | } 75 | }; 76 | 77 | // Sample usage: 78 | 79 | /* 80 | int main() { 81 | EdmondsKarp mf; 82 | mf.init(); 83 | 84 | // ... 85 | mf.addEdge(..., ...); 86 | 87 | s = // source 88 | t = // sink 89 | result = mf.maxflow(s, t); 90 | 91 | return 0; 92 | } 93 | */ 94 | 95 | -------------------------------------------------------------------------------- /Hash table/README.md: -------------------------------------------------------------------------------- 1 | # Hash Table 2 | 3 | Το hash table είναι μια δομή δεδομένων η οποία επιτρέπει να εισαχθούν, να διαγραφούν και να προσπελαστούν δεδομένα γρήγορα. Λειτουργεί όμοια με το map της stl στην c++ και πρακτικά ίδια με το unordered\_map της stl στην c++11. 4 | 5 | ## Περιγραφή του αλγορίθμου 6 | 7 | Το hash table αντιστοιχεί στο κάθε κλειδί (key) μία τιμή (value). Για να το κάνει αυτό, χρησιμοποιεί μια συνάρτηση κατακερματισμού (hashing) με την οποία αντιστοιχεί το κλειδί σε έναν αριθμό από το 0 μέχρι το μέγεθος του hash table. Μετά, εισάγει το ζευγάρι (κλειδί, τιμή) σε εκείνο το σημείο του hash table. Επειδή η συναρτήσεις κατακερματισμού δεν είναι τέλειες, μπορεί να έχουμε collisions, δηλαδή δύο κλειδιά με το ίδιο hash. Σύμφωνα με το birthday paradox, αυτό συμβαίνει με πιθανότητα ίση με την τετραγωνική ρίζα του μεγέθους του hash table. Για αυτόν τον λόγο σε κάθε σημείο του hash table δημιουργούμε ένα linked list και σε αυτό προσθέτουμε το ζευγάρι (κλειδί,τιμή). 8 | 9 | Στην υλοποίηση `source.c`, έχουμε μια λίγο διαφορετική μορφή hash table. Αντί να δημιουργούμε linked list, όσο υπάρχει collision, αυξάνουμε την θέση στην οποία θα μπει το ζευγάρι κατά ένα (και εάν γίνει μεγαλύτερη από τα όρια του πίνακα, την μηδενίζουμε). Αποδεικνύεται ότι και σε αυτήν την περίπτωση, η εισαγωγή, η αφαίρεση και η προσπέλαση είναι O(1). Μάλιστα, αυτή η υλοποίηση είναι συντομότερη στο γράψιμο, και θεωρητικά είναι κάπως πιο γρήγορη, διότι εκμεταλλεύεται το chaching και εκτελεί σειριακή προσπέλαση δεδομένων. Πρέπει όμως να προσέχουμε να έχουμε δεδομένα λιγότερα από όσο είναι το μέγεθος του πίνακα. 10 | -------------------------------------------------------------------------------- /Hash table/source.c: -------------------------------------------------------------------------------- 1 | #include // scanf, printf 2 | #include // malloc 3 | #include // memcpy, strlen, strcmp 4 | 5 | #define MAXHASH 1000003 // Είναι πρώτος αριθμός, άρα μειώνει τα collisions. Ανά πάσα στιγμή, το hash table πρέπει να έχει λιγότερες από MAXHASH λέξεις! 6 | #define WORDSIZE 32 // Το μέγιστο μέγεθος της κάθε λέξης (προσοχή! πρέπει να υπάρχει χώρος για έναν έξτρα χαρακτήρα στο τέλος που υποδηλώνει το τέλος της λέξης, οπότε στην πραγματικότητα το μέγιστο μέγεθος λέξης είναι 31) 7 | 8 | char keys[MAXHASH][WORDSIZE]; 9 | int values[MAXHASH]; 10 | 11 | int hash(char *key) { // Επιστρέφει έναν ακέραιο που αντιστοιχεί στο δεδομένο κλειδι. Για κάθε key1, key2, P[hash(key1)==hash(key2)]<=1/MAXHASH 12 | long long out=0; 13 | int s=strlen(key); 14 | for(int i=0; i // swap 7 | #include 8 | 9 | using namespace std; 10 | 11 | const int MAX_N = ; // <- insert value 12 | 13 | vector gr[MAX_N]; // adjacency list of the tree 14 | int from[MAX_N], to[MAX_N]; // subtree range 15 | int node_cnt; 16 | int sz[MAX_N]; // subtree size 17 | int head[MAX_N]; // chain head 18 | int par[MAX_N]; // parent node 19 | int lvl[MAX_N]; // node level 20 | 21 | void get_sz(int u) { 22 | sz[u] = 1; 23 | // par[root] = -1 24 | if (par[u] != -1) 25 | gr[u].erase(find(gr[u].begin(), gr[u].end(), par[u])); 26 | for (auto &v : gr[u]) { 27 | par[v] = u; 28 | lvl[v] = lvl[u] + 1; 29 | get_sz(v); 30 | sz[u] += sz[v]; 31 | if (sz[v] > sz[gr[u][0]]) 32 | swap(gr[u][0], v); 33 | } 34 | } 35 | 36 | void hld(int u) { 37 | from[u] = to[u] = node_cnt++; 38 | for (auto v : gr[u]) { 39 | if (v == gr[u][0]) 40 | head[v] = head[u]; 41 | else 42 | head[v] = v; 43 | hld(v); 44 | to[u] = to[v]; 45 | } 46 | } 47 | 48 | int LCA(int u, int v) { 49 | while (head[u] != head[v]) { 50 | if (lvl[head[u]] > lvl[head[v]]) 51 | u = par[head[u]]; 52 | else 53 | v = par[head[v]]; 54 | } 55 | if (lvl[u] > lvl[v]) 56 | return v; 57 | return u; 58 | } 59 | 60 | /* 61 | int main() { 62 | int root = ; // <- insert value 63 | 64 | lvl[root] = 0; 65 | par[root] = -1; 66 | get_sz(root); 67 | 68 | node_cnt = 0; 69 | head[root] = root; 70 | hld(root); 71 | 72 | return 0; 73 | } 74 | */ 75 | 76 | -------------------------------------------------------------------------------- /Kruskal/README.md: -------------------------------------------------------------------------------- 1 | # Ο αλγόριθμος του Kruskal - Εύρεση Minimum Spanning Tree 2 | 3 | Ο αλγόριθμος του Kruskal είναι ένας αλγόριθμος για την εύρεση του Minimum Spanning Tree, δηλαδή δεδομένου ενός συνδεδεμένου μη κατευθυνόμενου γράφου, βρίσκει το σύνολο με το ελάχιστο άθροισμα ακμών έτσι ώστε εάν αφαιρέσουμε όλες τις ακμές εκτός από αυτές, ο γράφος να παραμείνει συνδεδεμένος. 4 | 5 | ## Περιγραφή του αλγορίθμου 6 | 7 | Ο Kruskal βάζει ακμές στο σύνολο των ακμών που δεν σβήνουμε, όσο δεν δημιουργούνται κύκλοι. Εξετάζει τις ακμές με αυξανόμενο βάρος. Εάν κάποια ακμή κλείνει κύκλο, δεν την βάζει. Για να ελέγξει εάν δημιουργούνται κύκλοι, χρησιμοποιεί την δομή Disjoint Set. Η ταξινόμηση των ακμών στην αρχή έχει πολυπλοκότητα O(mlog m), αλλά κάθε πράξη της Disjoint Set είναι πολύ γρήγορη, σε O(a(n)), όπου a(n) είναι η συνάρτηση reverse ackermann, μία συνάρτηση που μεγαλώνει πάρα πολύ αργά. Επομένως, εάν έχουμε τις ακμές ήδη ταξινομημένες, ο αλγόριθμος έχει πολυπλοκότητα O(na(n)). -------------------------------------------------------------------------------- /Kruskal/source.cpp: -------------------------------------------------------------------------------- 1 | #include // scanf, printf 2 | #include // sort 3 | #include // queue 4 | 5 | using namespace std; 6 | 7 | #define MAXN 1000010 8 | #define MAXM 1000010 9 | 10 | struct el { 11 | int from, to, val; 12 | } edge[MAXM]; 13 | 14 | int height[MAXN], par[MAXN]; 15 | 16 | int Find(int now) { 17 | if(now!=par[now]) { 18 | par[now]=Find(par[now]); 19 | } 20 | return par[now]; 21 | } 22 | 23 | void Union(int from, int to) { 24 | (void)Find(from); 25 | (void)Find(to); 26 | 27 | if(height[par[from]]height[par[to]]) { 31 | par[par[to]]=par[from]; 32 | } 33 | else { 34 | par[par[to]]=par[from]; 35 | ++height[par[from]]; 36 | } 37 | } 38 | 39 | bool comp(el u, el v) { 40 | return u.val out; 58 | 59 | for(int i=1; i<=M; ++i) { 60 | if(Find(edge[i].from)!=Find(edge[i].to)) { 61 | out.push(edge[i]); 62 | weight+=edge[i].val; 63 | Union(edge[i].from, edge[i].to); 64 | } 65 | } 66 | 67 | printf("MST total weight: %d\n", weight); 68 | printf("MST contains:\n"); 69 | while(!out.empty()) { 70 | printf("(%d, %d, %d) ", out.front().from, out.front().to, out.front().val); 71 | out.pop(); 72 | } 73 | printf("\n"); 74 | return 0; 75 | } 76 | 77 | -------------------------------------------------------------------------------- /Li_Chao_Tree/source.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Min Li Chao Segment Tree για το πλήρως δυναμικό Convex Hull Trick (CHT). 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | // Προσέξτε για overflows όταν επιλέγετε τύπο μεταβλητής! 11 | typedef long long ftype; 12 | 13 | const int MAX_N = 1e5 + 5; 14 | 15 | struct line { 16 | ftype m, b; 17 | } tree[MAX_N * 4]; 18 | 19 | ftype func(line f, ftype x) { 20 | return f.m * x + f.b; 21 | } 22 | 23 | // Αρχικοποιούμε με μία ακραία τιμή που ποτέ δεν 24 | // πρόκειται να είναι η απάντηση. 25 | void init() { 26 | // Αλλάξτε αυτό για το max CHT ή αν χρειάζεστε 27 | // μικρότερο τύπο μεταβλητής από long long. 28 | line sentinel = (line){0, (ftype)1e18}; 29 | fill(tree, tree + MAX_N * 4, sentinel); 30 | } 31 | 32 | void add_line(int p, int L, int R, line nw) { 33 | int left = p << 1, right = left | 1; 34 | int mid = (L + R) >> 1; 35 | // Αλλάξτε τη σειρά σύγκρισης στις δυο επόμενες γραμμές 36 | // για το MAX CHT. 37 | bool left_check = func(nw, L) < func(tree[p], L); 38 | bool mid_check = func(nw, mid) < func(tree[p], mid); 39 | if (mid_check) 40 | swap(tree[p], nw); 41 | if (L == R) 42 | return; 43 | if (left_check != mid_check) { 44 | add_line(left, L, mid, nw); 45 | } 46 | else { 47 | add_line(right, mid + 1, R, nw); 48 | } 49 | } 50 | 51 | // Προσέξτε ότι το x θα πρέπει να είναι 52 | // μεταξύ του L και του R. 53 | ftype query(int p, int L, int R, int x) { 54 | ftype res = func(tree[p], x); 55 | if (L == R) 56 | return res; 57 | int left = p << 1, right = left | 1; 58 | int mid = (L + R) >> 1; 59 | if (x <= mid) { 60 | // Αλλάξτε το min σε max αν θέλετε το max CHT. 61 | return min(res, query(left, L, mid, x)); 62 | } 63 | else { 64 | // Αλλάξτε το min σε max αν θέλετε το max CHT. 65 | return min(res, query(right, mid + 1, R, x)); 66 | } 67 | } 68 | 69 | int main() { 70 | init(); 71 | add_line(1, 0, MAX_N - 1, (line){1, -325}); 72 | add_line(1, 0, MAX_N - 1, (line){-100, 3}); 73 | add_line(1, 0, MAX_N - 1, (line){1000, -3421}); 74 | printf("%lld\n", query(1, 0, MAX_N - 1, 24123)); 75 | printf("%lld\n", query(1, 0, MAX_N - 1, 154)); 76 | return 0; 77 | } 78 | 79 | -------------------------------------------------------------------------------- /Lowest Common Ancestor/source.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Lowest Common Ancestor implementation with the binary lifting technique. 3 | - O(N log N) precomputation 4 | - O(log N) per query 5 | */ 6 | 7 | #include // memset 8 | #include 9 | 10 | using namespace std; 11 | 12 | const int MAX_N = ; // <- insert value 13 | const int LOGN = ; // <- insert value 14 | 15 | vector gr[MAX_N]; // adjacency list of the tree 16 | int par[MAX_N][LOGN]; // binary lifting table 17 | int lvl[MAX_N]; // node level 18 | 19 | void init(int u) { 20 | for (int j = 1; j < LOGN; j++) 21 | if (par[u][j - 1] != -1) 22 | par[u][j] = par[par[u][j - 1]][j - 1]; 23 | for (auto v : gr[u]) { 24 | if (v == par[u][0]) continue; 25 | par[v][0] = u; 26 | lvl[v] = lvl[u] + 1; 27 | init(v); 28 | } 29 | } 30 | 31 | int LCA(int u, int v) { 32 | if (lvl[v] > lvl[u]) swap(u, v); 33 | for (int j = LOGN - 1; j >= 0; j--) 34 | if (lvl[v] + (1 << j) <= lvl[u]) 35 | u = par[u][j]; 36 | if (u == v) return u; 37 | for (int j = LOGN - 1; j >= 0; j--) 38 | if (par[u][j] != -1 && par[u][j] != par[v][j]) 39 | u = par[u][j], v = par[v][j]; 40 | return par[u][0]; 41 | } 42 | 43 | /* 44 | int main() { 45 | int root = ; // <- insert value 46 | 47 | memset(par, -1, sizeof par); 48 | 49 | lvl[root] = 0; 50 | init(root); 51 | 52 | return 0; 53 | } 54 | */ 55 | 56 | -------------------------------------------------------------------------------- /Lowest Common Ancestor/source2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Lowest Common Ancestor implementation with euler tour + sparse table. 3 | - O(N log N) precomputation 4 | - O(1) per query 5 | */ 6 | 7 | #include // min, max 8 | #include 9 | 10 | using namespace std; 11 | 12 | const int MAX_N = ; // <- insert value 13 | // LOGN must be equal to log2(3 * MAX_N) 14 | const int LOGN = ; // <- insert value 15 | 16 | vector gr[MAX_N]; // adjacency list of the tree 17 | int euler[MAX_N * 3]; // tree euler tour (DFS-order) 18 | int in[MAX_N], out[MAX_N]; // in and out time of DFS 19 | int lvl[MAX_N]; // node level 20 | int node_cnt; 21 | int spt[LOGN][MAX_N * 3]; // sparse table 22 | int lg[MAX_N * 3]; // array of logs (base 2) 23 | 24 | void init(int u, int p = -1) { 25 | in[u] = out[u] = node_cnt; 26 | euler[node_cnt++] = u; 27 | 28 | for (auto v : gr[u]) { 29 | if (v == p) continue; 30 | lvl[v] = lvl[u] + 1; 31 | init(v, u); 32 | out[u] = node_cnt; 33 | euler[node_cnt++] = u; 34 | } 35 | } 36 | 37 | void buildSPT() { 38 | lg[1] = 0; 39 | for (int i = 2; i < MAX_N * 3; i++) 40 | lg[i] = lg[i >> 1] + 1; 41 | int n = node_cnt; 42 | for (int i = 0; i < n; i++) 43 | spt[0][i] = euler[i]; 44 | for (int j = 1; (1 << j) <= n; j++) { 45 | for (int i = 0; i + (1 << j) - 1 < n; i++) 46 | if (lvl[spt[j - 1][i]] < lvl[spt[j - 1][i + (1 << (j - 1))]]) 47 | spt[j][i] = spt[j - 1][i]; 48 | else 49 | spt[j][i] = spt[j - 1][i + (1 << (j - 1))]; 50 | } 51 | } 52 | 53 | int LCA(int u, int v) { 54 | int i = min(in[u], in[v]); 55 | int j = max(out[u], out[v]); 56 | int log = lg[j - i + 1]; 57 | int a = spt[log][i], b = spt[log][j - (1 << log) + 1]; 58 | if (lvl[a] < lvl[b]) 59 | return a; 60 | return b; 61 | } 62 | /* 63 | int main() { 64 | int root = ; // <- insert value 65 | 66 | node_cnt = 0; 67 | lvl[root] = 0; 68 | 69 | init(root); 70 | buildSPT(); 71 | 72 | return 0; 73 | } 74 | */ 75 | -------------------------------------------------------------------------------- /Merge heap/README.md: -------------------------------------------------------------------------------- 1 | # Merge heap 2 | 3 | Η merge heap (ή αλλιώς meld heap) είναι μια randomized δομή δεδομένων. Είναι ιδιαίτερα εύκολη στην υλοποίηση, καθώς όλες οι πράξεις της heap υλοποιούνται με μία και μόνο συνάρτηση, την `merge`. Η υλοποίηση που παρέχουμε εδώ στο `source.cpp` κάνει heap sort χρησιμοποιώντας την merge heap. 4 | 5 | ## Περιγραφή του αλγορίθμου 6 | 7 | Καθώς ο αλγόριθμος αποτελείται ουσιαστικά από μία και μόνο συνάρτηση, χρειάζεται να περιγράψουμε μόνο αυτήν. Για να ενώσουμε δύο heaps, αρκεί να επιλέξουμε τυχαία εάν η ρίζα της heap με τη μεγαλύτερη κορυφή θα καταλήξει στο αριστερό ή στο δεξί παιδί της heap με τη μικρότερη κορυφή. Αφού το αποφασίσουμε αυτό, απλά κάνουμε αναδρομικά merge την heap με την μεγαλύτερη κορυφή, με το αντίστοιχο παιδί της heap με την μικρότερη κορυφή. Αποδεικνύεται ότι με αυτόν τον τρόπο, η merge έχει πολυπλοκότητα O(log n). -------------------------------------------------------------------------------- /Merge heap/source.cpp: -------------------------------------------------------------------------------- 1 | #include // scanf, printf 2 | #include // rand, srand 3 | #include // time 4 | #include // swap 5 | 6 | using namespace std; 7 | 8 | struct heap { 9 | heap *l, *r; 10 | int val; 11 | } *h; 12 | 13 | heap* merge(heap *h1, heap *h2) { // Ενώνει τις δύο heap h1 και h2 14 | if(h1==NULL) { 15 | return h2; 16 | } 17 | if(h2==NULL) { 18 | return h1; 19 | } 20 | 21 | if(h2->val < h1->val) { 22 | swap(h1, h2); 23 | } 24 | if(rand()%2==1) { 25 | swap(h1->l, h1->r); 26 | } 27 | 28 | h1->l=merge(h1->l, h2); 29 | return h1; 30 | } 31 | 32 | void insert(int val) { // Εισάγει την τιμή val στην heap 33 | heap *h1=(heap*)malloc(sizeof(heap)); 34 | h1->l=NULL; 35 | h1->r=NULL; 36 | h1->val=val; 37 | h=merge(h1, h); 38 | } 39 | 40 | int find_min() { // Τυπώνει την ελάχιστη τιμή της heap 41 | return h->val; 42 | } 43 | 44 | void delete_min() { // Αφαιρεί την ελάχιστη τιμή από την heap 45 | h=merge(h->l, h->r); 46 | } 47 | 48 | int main() { 49 | srand(time(NULL)); 50 | int N, num; 51 | scanf("%d", &N); 52 | for(int i=1; i<=N; ++i) { 53 | scanf("%d", &num); 54 | insert(num); 55 | } 56 | 57 | for(int i=1; i<=N; ++i) { 58 | num=find_min(); 59 | delete_min(); 60 | printf("%d ", num); 61 | } 62 | printf("\n"); 63 | return 0; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /Min-Cost Max-Flow/source.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Successive Shortest Paths Algorithm for computing Min-Cost Max-Flow. Basically, it is just Edmonds-Karp with Bellman-Ford instead of BFS for getting an augmenting path. 3 | Works in O(V ^ 2 * E ^ 2) worst case. 4 | Implementation also supports multiple edges. 5 | The graph must not contain a negative cycle at the time of calling the compute function. 6 | */ 7 | #include // fill, min 8 | #include // memset 9 | #include // pair, make_pair 10 | #include // numeric_limits 11 | #include 12 | 13 | using namespace std; 14 | 15 | template 16 | struct mcmf { 17 | static const int NODES = ; // <- insert value 18 | // Be carefule to set 2 * #ofedges because we count each one twice 19 | // (they are bidirectional in the residual network). 20 | static const int EDGES = ; // <- insert value 21 | 22 | // Intentionally set INF_MC = MAX_VAL / 2 so that Bellamn Ford 23 | // will not crush. 24 | static const t_mc INF_MC = numeric_limits::max() / 2; 25 | static const t_mf INF_MF = numeric_limits::max(); 26 | 27 | vector adj[NODES]; 28 | t_mf cap[EDGES]; 29 | t_mc wgt[EDGES], dist[NODES]; 30 | int to[EDGES], cnt_ed = 0; 31 | int p[NODES], pe[NODES], max_node; 32 | 33 | void init(int mx_nd) { 34 | max_node = mx_nd; 35 | fill(adj, adj + NODES, vector()); 36 | cnt_ed = 0; 37 | } 38 | 39 | void addEdge(int u, int v, t_mf c, t_mc w) { 40 | adj[u].push_back(cnt_ed); 41 | to[cnt_ed] = v; 42 | cap[cnt_ed] = c; 43 | wgt[cnt_ed] = w; 44 | cnt_ed++; 45 | 46 | adj[v].push_back(cnt_ed); 47 | to[cnt_ed] = u; 48 | cap[cnt_ed] = 0; 49 | wgt[cnt_ed] = -w; 50 | cnt_ed++; 51 | } 52 | 53 | bool BellmanFord(int s, int t) { 54 | memset(p, -1, sizeof p); 55 | fill(dist, dist + max_node + 1, INF_MC); 56 | dist[s] = 0; 57 | bool changed = true; 58 | for (int i = 0; i <= max_node && changed; i++) { 59 | changed = false; 60 | for (int u = 0; u <= max_node; u++) { 61 | for (auto e : adj[u]) { 62 | int v = to[e]; 63 | if (cap[e] > ( t_mf )0 && dist[u] + wgt[e] < dist[v]) { 64 | dist[v] = dist[u] + wgt[e]; 65 | p[v] = u; 66 | pe[v] = e; 67 | changed = true; 68 | } 69 | } 70 | } 71 | } 72 | return p[t] != -1; 73 | } 74 | 75 | pair compute(int s, int t) { 76 | t_mc mc = 0; 77 | t_mf mf = 0; 78 | while (BellmanFord(s, t)) { 79 | t_mf f = INF_MF; 80 | for (int u = t; u != s; u = p[u]) 81 | f = min(f, cap[pe[u]]); 82 | if (f == ( t_mf )0) break; 83 | for (int u = t; u != s; u = p[u]) { 84 | cap[pe[u]] -= f; 85 | cap[pe[u] ^ 1] += f; 86 | } 87 | mf += f; 88 | mc += dist[t] * f; 89 | } 90 | return make_pair(mc, mf); 91 | } 92 | }; 93 | 94 | /* 95 | int main() { 96 | mcmf box; 97 | 98 | s = // source 99 | t = // sink 100 | 101 | box.init(max_node_value); 102 | 103 | int mc, mf; 104 | tie(mc, mf) = box.compute(s, t); 105 | 106 | return 0; 107 | } 108 | */ 109 | 110 | -------------------------------------------------------------------------------- /Monotone chain/README.md: -------------------------------------------------------------------------------- 1 | # Monotone Chain 2 | 3 | Ο αλγόριθμος Monotone Chain βρίσκει την κυρτή θήκη ενός συνόλου N σημείων σε O(NlogN). Η κυρτή θήκη ορίζεται ως το πολύγωνο με τη μικρότερη περίμετρο το οποίο περιέχει όλα τα σημεία. 4 | 5 | ## Περιγραφή του αλγορίθμου 6 | 7 | Αρχικά ταξινομούμε τα σημεία ως προς την τετμημένη με αύξουσα σειρά. Παρατηρούμε ότι το αριστερότερο και το δεξιότερο σημείο (ή, σε περίπτωση περισσότερων από ένα σημείο, το αριστερότερο και κατώτερο, και δεξιότερο και ανώτερο) θα είναι αναγκαστικά σημεία της κυρτής θήκης. Μπορούμε να χωρίσουμε την κυρτή θήκη σε δύο "αλυσίδες", την ανώτερη αλυσίδα (upper chain), η οποία περιέχει τα σημεία που βρίσκονται δεξιόστροφα στη διαδρομή από το αριστερότερο σημείο προς το δεξιότερο, και την κατώτερη αλυσίδα (lower chain), η οποία περιέχει τα σημεία που βρίσκονται δεξιόστροφα στη διαδρομή από το δεξιότερο σημείο προς το αριστερότερο.Αρκεί λοιπόν να υπολογίσουμε τις δύο αυτές αλυσίδες. Θα χρησιμοποιήσουμε την συνάρτηση CCW (Counter-ClockWise), η οποία δέχεται τρία σημεία A,B,C, και επιστρέφει θετικό αριθμό αν το σημείο C βρίσκεται αριστερόστροφα της ημιευθείας που ξεκινάει από το A και περνάει από το B, μηδέν στην περίπτωση που είναι συνευθειακά, και αρνητικό αριθμό σε κάθε άλλη περίπτωση. Χρησιμοποιώντας την συνάρτηση αυτή, μπορούμε σε ένα πέρασμα του πίνακα των σημείων να δημιουργήσουμε το upper chain, εισάγοντας τα σημεία σε μία στοίβα (stack) με την ιδιότητα ότι τα τρία τελευταία στοιχεία της στοίβας έχουν αρνητικό CCW. Το ίδιο ακριβώς (απλώς με αντίστροφη σειρά προσθήκης σημείων) μπορούμε να κάνουμε για να δημιουργήσουμε το lower chain. Συνδυάζοντας αυτές τις δύο αλυσίδες, μπορούμε να βρούμε την απάντηση. 8 | -------------------------------------------------------------------------------- /Monotone chain/source.cpp: -------------------------------------------------------------------------------- 1 | #include // scanf, printf 2 | #include // sqrt 3 | #include // sort 4 | #include // pair 5 | 6 | using namespace std; 7 | 8 | #define X first 9 | #define Y second 10 | #define mp make_pair 11 | #define pii pair 12 | #define llint long long 13 | #define pll pair 14 | #define sq(x) ((x)*(x)) 15 | #define MAXN 100010 16 | 17 | llint CCW(pll A, pll B, pll C) { // CCW = Counter-ClockWise. Θεωρητικά εσωτερικό γινόμενο των διανυσμάτων (A-B) και (C-B) (επί δύο). Είναι θετικό αν και μόνο αν το σημείο C είναι αριστερά της ευθείας που περνάει από τα A,B. Είναι μηδέν όταν τα A, B, C είναι συνευθειακά. 18 | return A.X*B.Y-A.Y*B.X+B.X*C.Y-B.Y*C.X+C.X*A.Y-C.Y*A.X; 19 | } 20 | 21 | double dist(pll u, pll v) { // Απόσταση των σημείων u και v 22 | return sqrt(sq(u.X-v.X)+sq(u.Y-v.Y)); 23 | } 24 | 25 | int N, hull[MAXN]; 26 | pii pt[MAXN]; 27 | 28 | int main() { 29 | scanf("%d", &N); 30 | for(int i=1; i<=N; ++i) { 31 | scanf("%d %d", &pt[i].X, &pt[i].Y); 32 | } 33 | sort(pt+1, pt+N+1); 34 | 35 | int top=0; 36 | for(int i=1; i<=N; ++i) { // Υπολογισμός του upper envelope 37 | while(top>=2 && CCW(pt[hull[top-1]], pt[hull[top]], pt[i])>=0) { 38 | --top; 39 | } 40 | hull[++top]=i; 41 | } 42 | for(int i=N-1; i>=1; --i) { // Υπολογισμός του lower envelope 43 | while(top>=2 && CCW(pt[hull[top-1]], pt[hull[top]], pt[i])>=0) { 44 | --top; 45 | } 46 | hull[++top]=i; 47 | } 48 | 49 | double length=0; 50 | printf("Convex Hull:\n"); 51 | for(int i=1; i // printf, scanf 2 | #include // pair 3 | #include // vector 4 | #include // set 5 | #include // queue 6 | 7 | using namespace std; 8 | 9 | #define mp make_pair 10 | #define pb push_back 11 | #define X first 12 | #define Y second 13 | #define MAXN 100000 14 | 15 | int N, M, S, D; 16 | bool vis[MAXN]; 17 | vector adj[MAXN], dist[MAXN]; 18 | queue, int> > out; 19 | 20 | int Prim() { 21 | int weight=0; 22 | pair > now; 23 | set > > pq; 24 | pq.insert(mp(0, mp(1, 0))); 25 | 26 | while(!pq.empty()) { 27 | now=*pq.begin(); 28 | pq.erase(pq.begin()); 29 | 30 | if(vis[now.Y.X]) { 31 | continue; 32 | } 33 | vis[now.Y.X]=true; 34 | weight+=now.X; 35 | out.push(mp(mp(now.Y.X, now.Y.Y), now.X)); 36 | 37 | for(size_t i=0; i // scanf, printf 2 | #include // rand, srand 3 | #include // time 4 | #include // swap 5 | 6 | using namespace std; 7 | 8 | #define MAXN 1000010 9 | 10 | int inpt[MAXN]; 11 | 12 | void quicksort(int *arr, int n) { 13 | if(n<=1) { 14 | return; 15 | } 16 | int m=rand()%n; 17 | swap(arr[0], arr[m]); 18 | m=0; 19 | for(int i=1; i // scanf, printf 2 | #include // rand, srand 3 | #include // time 4 | 5 | #define MAXPRIOR 0x3f3f3f3f 6 | 7 | struct el { 8 | el *lft, *rgt; 9 | int key, prior, siz; 10 | 11 | el(int key) { 12 | this->key=key; 13 | prior=rand()%MAXPRIOR; 14 | siz=1; 15 | lft=NULL; 16 | rgt=NULL; 17 | } 18 | } *root; 19 | typedef el* elpt; 20 | 21 | int siz(el *now) { // Επιστρέφει το μέγεθος του υποδέντρου με ρίζα το now 22 | if(now==NULL) { 23 | return 0; 24 | } 25 | return now->siz; 26 | } 27 | 28 | void update(el *now) { // Ενημερώνει το μέγεθος του now 29 | if(now==NULL) { 30 | return; 31 | } 32 | now->siz=siz(now->lft)+siz(now->rgt)+1; 33 | } 34 | 35 | void Merge(elpt &now, elpt lft, elpt rgt) { // Ενώνει τις treaps lft και rgt και αποθηκεύει το αποτέλεσμα στο now 36 | if(lft==NULL) { 37 | now=rgt; 38 | return; 39 | } 40 | if(rgt==NULL) { 41 | now=lft; 42 | return; 43 | } 44 | 45 | if(lft->priorprior) { 46 | Merge(lft->rgt, lft->rgt, rgt); 47 | now=lft; 48 | } 49 | else { 50 | Merge(rgt->lft, lft, rgt->lft); 51 | now=rgt; 52 | } 53 | 54 | update(now); 55 | } 56 | 57 | void Split(elpt now, elpt &lft, elpt &rgt, int key) { // Χωρίζει την treap now στις treaps lft και rgt με βάση το κλειδί key 58 | if(now==NULL) { 59 | lft=NULL; 60 | rgt=NULL; 61 | return; 62 | } 63 | 64 | if(now->key<=key) { 65 | Split(now->rgt, now->rgt, rgt, key); 66 | lft=now; 67 | } 68 | else { 69 | Split(now->lft, lft, now->lft, key); 70 | rgt=now; 71 | } 72 | 73 | update(lft); 74 | update(rgt); 75 | } 76 | 77 | void Insert(int val) { // Εισάγει ένα στοιχείο με κλειδί val στην treap 78 | el *tmp=new el(val), *t1, *t2; 79 | Split(root, t1, t2, val); 80 | Merge(t1, t1, tmp); 81 | Merge(root, t1, t2); 82 | } 83 | 84 | void Delete(int val) { // Σβήνει όλα τα στοιχεία με κλειδί val από την treap 85 | el *t1, *t2; 86 | Split(root, root, t2, val); 87 | Split(root, t1, root, val-1); 88 | Merge(root, t1, t2); 89 | } 90 | 91 | int FindPosition(int val) { // Βρίσκει την θέση του πρώτου στοιχείου με κλειδί val (εάν τα στοιχεία ήταν ταξινομημένα) 92 | el *t1, *t2; 93 | bool flag=true; 94 | Split(root, root, t2, val); 95 | Split(root, t1, root, val-1); 96 | if(root==NULL) { 97 | flag=false; 98 | } 99 | Merge(root, t1, root); 100 | Merge(root, root, t2); 101 | if(!flag) { 102 | return -1; 103 | } 104 | Split(root, t1, t2, val-1); 105 | int out=siz(t1); 106 | Merge(root, t1, t2); 107 | return out; 108 | } 109 | 110 | int main() { 111 | int Q, val; 112 | char op; 113 | scanf("%d\n", &Q); 114 | srand(time(NULL)); 115 | for(int i=1; i<=Q; ++i) { 116 | scanf("%c %d\n", &op, &val); 117 | if(op=='I') { 118 | Insert(val); 119 | } 120 | else if(op=='D') { 121 | Delete(val); 122 | } 123 | else if(op=='P') { 124 | int tmp=FindPosition(val); 125 | if(tmp==-1) { 126 | printf("%d cannot be found\n", val); 127 | } 128 | else { 129 | printf("%d is in position %d\n", val, tmp); 130 | } 131 | } 132 | } 133 | return 0; 134 | } 135 | 136 | -------------------------------------------------------------------------------- /Treap/source2.cpp: -------------------------------------------------------------------------------- 1 | #include // scanf, printf 2 | #include // rand, srand 3 | #include // time 4 | #include // swap 5 | 6 | using namespace std; 7 | 8 | #define MAXPRIOR 0x3f3f3f3f 9 | 10 | struct el { 11 | el *lft, *rgt; 12 | int val, prior, siz; 13 | bool islazy; 14 | 15 | el(int val) { 16 | this->val=val; 17 | prior=rand()%MAXPRIOR; 18 | siz=1; 19 | islazy=false; 20 | lft=NULL; 21 | rgt=NULL; 22 | } 23 | } *root; 24 | typedef el* elpt; 25 | 26 | int siz(el *now) { // Επιστρέφει το μέγεθος του υποδέντρου με ρίζα το now 27 | if(now==NULL) { 28 | return 0; 29 | } 30 | return now->siz; 31 | } 32 | 33 | void update(el *now) { // Ενημερώνει το μέγεθος του now 34 | if(now==NULL) { 35 | return; 36 | } 37 | now->siz=siz(now->lft)+siz(now->rgt)+1; 38 | } 39 | 40 | void propagate(el *now) { // Ενημερώνει τα παιδιά του now για το αν έχουν αντιστραφεί τα στοιχεία τους 41 | if(now==NULL || !now->islazy) { 42 | return; 43 | } 44 | swap(now->lft, now->rgt); 45 | if(now->lft!=NULL) { 46 | now->lft->islazy^=true; 47 | } 48 | if(now->rgt!=NULL) { 49 | now->rgt->islazy^=true; 50 | } 51 | now->islazy=false; 52 | } 53 | 54 | void Merge(elpt &now, elpt lft, elpt rgt) { // Ενώνει τις treaps lft και rgt και αποθηκεύει το αποτέλεσμα στο now 55 | if(lft==NULL) { 56 | now=rgt; 57 | return; 58 | } 59 | if(rgt==NULL) { 60 | now=lft; 61 | return; 62 | } 63 | 64 | propagate(lft); 65 | propagate(rgt); 66 | 67 | if(lft->priorprior) { 68 | Merge(lft->rgt, lft->rgt, rgt); 69 | now=lft; 70 | } 71 | else { 72 | Merge(rgt->lft, lft, rgt->lft); 73 | now=rgt; 74 | } 75 | 76 | update(now); 77 | } 78 | 79 | void Split(elpt now, elpt &lft, elpt &rgt, int pos, int offset=0) { // Χωρίζει την treap now στις treaps lft και rgt με βάση την θέση pos 80 | if(now==NULL) { 81 | lft=NULL; 82 | rgt=NULL; 83 | return; 84 | } 85 | 86 | propagate(now); 87 | int nowpos=siz(now->lft)+offset; 88 | 89 | if(nowpos<=pos) { 90 | Split(now->rgt, now->rgt, rgt, pos, nowpos+1); 91 | lft=now; 92 | } 93 | else { 94 | Split(now->lft, lft, now->lft, pos, offset); 95 | rgt=now; 96 | } 97 | 98 | update(lft); 99 | update(rgt); 100 | } 101 | 102 | void Insert(int pos, int val) { // Βάζει ένα στοιχείο στη θέση pos το οποίο έχει τιμή val, και μετακινεί τα στοιχεία μετά από αυτό μία θέση προς τα δεξιά 103 | el *tmp=new el(val), *t1, *t2; 104 | Split(root, t1, t2, pos-1); 105 | Merge(t1, t1, tmp); 106 | Merge(root, t1, t2); 107 | } 108 | 109 | void Delete(int pos) { // Σβήνει το στοιχείο στη θέση pos, και μετακινεί τα στοιχεία μετά από αυτό μία θέση προς τα αριστερά 110 | el *t1, *t2; 111 | Split(root, root, t2, pos); 112 | Split(root, t1, root, pos-1); 113 | Merge(root, t1, t2); 114 | } 115 | 116 | void Reverse(int from, int to) { // Αντιστρέφει τη σειρά των στοιχείων από τη θέση from μέχρι και τη θέση to 117 | el *t1, *t2; 118 | Split(root, root, t2, to); 119 | Split(root, t1, root, from-1); 120 | root->islazy^=true; 121 | Merge(root, t1, root); 122 | Merge(root, root, t2); 123 | } 124 | 125 | int Find(int pos) { // Επιστρέφει την τιμή του στοιχείου στη θέση pos 126 | el *t1, *t2; 127 | Split(root, root, t2, pos); 128 | Split(root, t1, root, pos-1); 129 | int out=root->val; 130 | Merge(root, t1, root); 131 | Merge(root, root, t2); 132 | return out; 133 | } 134 | 135 | int main() { 136 | int Q, pos, val, from, to; 137 | char op; 138 | scanf("%d\n", &Q); 139 | srand(time(NULL)); 140 | for(int i=1; i<=Q; ++i) { 141 | scanf("%c", &op); 142 | if(op=='I') { 143 | scanf("%d %d\n", &pos, &val); 144 | Insert(pos, val); 145 | } 146 | else if(op=='D') { 147 | scanf("%d\n", &pos); 148 | Delete(pos); 149 | } 150 | else if(op=='R') { 151 | scanf("%d %d\n", &from, &to); 152 | Reverse(from, to); 153 | } 154 | else if(op=='F') { 155 | scanf("%d", &pos); 156 | printf("%d\n", Find(pos)); 157 | } 158 | } 159 | return 0; 160 | } 161 | 162 | -------------------------------------------------------------------------------- /Virtual Tree/source.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Virtual Tree implementation based on https://blog.sengxian.com/algorithms/virtual-tree (in Chinese). 3 | 4 | Build in O(L log N) where L = # of Virtual Tree nodes 5 | */ 6 | #include // sort 7 | #include 8 | 9 | using namespace std; 10 | 11 | const int MAX_N = ; // <- insert value 12 | 13 | // NOTE: nodes are 1-based indexed 14 | vector gr[MAX_N]; // adjacency list of the tree 15 | int stk[MAX_N]; 16 | int dfn[MAX_N]; // DFS-order time 17 | int lvl[MAX_N]; // node level 18 | int df_counter; 19 | 20 | bool comp(int a, int b) { 21 | return dfn[a] < dfn[b]; 22 | } 23 | 24 | // NOTE: need to specify the content of this function 25 | void addEdge(int u, int v) { 26 | // ... 27 | // e.g. tree[u].push_back(v) 28 | } 29 | 30 | void dfs(int u, int p = -1) { 31 | dfn[u] = df_counter++; 32 | for (auto v : gr[u]) { 33 | if (v == p) continue; 34 | lvl[v] = lvl[u] + 1; 35 | dfs(v); 36 | } 37 | } 38 | 39 | int LCA(int u, int v) { 40 | // fill in this function 41 | } 42 | 43 | // returns the VT nodes 44 | vector buildVT(vector vtx) { 45 | sort(vtx.begin(), vtx.end(), comp); 46 | 47 | int top = 0; 48 | 49 | lvl[0] = -1; 50 | stk[top++] = 0; 51 | 52 | int L = (int)vtx.size(); 53 | for (int i = 0; i < L; i++) { 54 | int u = vtx[i]; 55 | int p = LCA(u, stk[top - 1]); 56 | while (top >= 2 && lvl[stk[top - 2]] >= lvl[p]) { 57 | addEdge(stk[top - 2], stk[top - 1]); 58 | top--; 59 | } 60 | 61 | if (stk[top - 1] != p) { 62 | addEdge(p, stk[top - 1]); 63 | top--; 64 | stk[top++] = p; 65 | vtx.push_back(p); 66 | } 67 | 68 | stk[top++] = u; 69 | } 70 | 71 | for (int i = 1; i < top - 1; i++) { 72 | addEdge(stk[i], stk[i + 1]); 73 | } 74 | 75 | return vtx; 76 | } 77 | 78 | /* 79 | int main() { 80 | computeLCA(); 81 | df_counter = 0; 82 | lvl[1] = 0; 83 | dfs(1); 84 | vector vtx = ; // <- insert value 85 | vtx = buildVT(vtx); 86 | return 0; 87 | } 88 | */ 89 | 90 | --------------------------------------------------------------------------------