Advertisement
Guest User

Untitled

a guest
Sep 17th, 2018
277
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.13 KB | None | 0 0
  1. /**
  2. Tip sursa: oficiala (+ comentarii)
  3. Autor: Alexandru Petrescu
  4. Complexitate timp: O(N * logN)
  5. Complexitate memorie: O(N)
  6. Punctaj asteptat: 100
  7. **/
  8.  
  9. #include <cstdio>
  10. #include <algorithm>
  11.  
  12. FILE *fin = fopen("nespus.in", "r"), *fout = fopen("nespus.out", "w");
  13.  
  14. #define INF 1000000000
  15.  
  16. #define MAXN 1000000
  17.  
  18. int w, val[2 * MAXN], urm[2 * MAXN], lista[MAXN + 1]; /// listele de adiacenta - retinerea grafului
  19. int viz[MAXN + 1], timp; /// fiecare bfs la "timp"-ul lui - "viz[x]" = ultimul timp (bfs) in care am dat peste nodul "x"
  20. int u[MAXN + 1]; /// "u[x]" = multimea din care face parte nodul "x"
  21. int s[2 * MAXN + 1]; /// "s[i]" = numarul de noduri din multimea cu indicele "i"; "s[0]" = numarul de multimi create
  22. int st[2], dr[2], q[2][MAXN + 1]; /// 2 cozi pentru bfs in paralel
  23. struct myc {
  24.     int x, y, z;
  25. } m[MAXN]; /// muchiile din input
  26.  
  27. inline void baga(int x, int y) { /// folosim liste de adiacenta pentru a retine graful
  28.     w++;
  29.     val[w] = y;
  30.     urm[w] = lista[x];
  31.     lista[x] = w;
  32. }
  33.  
  34. inline void inserare(int x, int g) {
  35.     q[g][dr[g]++] = x;
  36.     if (x != -1)
  37.         viz[x] = timp;
  38. }
  39.  
  40. inline void vezi(int x, int g) { /// consideram vecinii lui "x" si ii mutam in coada "g"
  41.     /**
  42.     Observatie
  43.         Muchiile gasite care duc catre noduri care nu apartin aceleiasi multimi se vor sterge
  44.     **/
  45.     /// nu intram in detalii, ori stii, ori nu stii sa manipulezi listele de adiacenta
  46.     while (lista[x] != 0 && u[x] != u[val[lista[x]]])
  47.         lista[x] = urm[lista[x]];
  48.     if (lista[x] != 0 && viz[val[lista[x]]] != timp)
  49.         inserare(val[lista[x]], g);
  50.     int p = urm[lista[x]], q = lista[x];
  51.     while (p != 0) {
  52.         if (u[x] == u[val[p]]) {
  53.             urm[q] = p;
  54.             q = p;
  55.             if (viz[val[p]] != timp)
  56.                 inserare(val[p], g);
  57.         }
  58.         p = urm[p];
  59.     }
  60. }
  61.  
  62. inline void bfs(int a, int b, int h) {
  63.     /**
  64.     - daca "a" este "-1", vizitam din "b" toate nodurile care apartin aceleiasi multimi si le fixam "h" ca multimea careia apartin mai nou
  65.     - altfel, parcurgem in paralel subarborii lui "a" si "b" pentru a-i atrbui celui mai mic dintre ele multimea cu indicele "h"
  66.     **/
  67.  
  68.     timp++; /// urmeaza un nou bfs
  69.  
  70.     st[0] = dr[0] = st[1] = dr[1] = 0;
  71.     inserare(a, 0);
  72.     inserare(b, 1);
  73.     int g = 1;
  74.     while (st[0] < dr[0] && st[1] < dr[1]) {
  75.         vezi(q[g][st[g]++], g);
  76.         if (a != -1)
  77.             g ^= 1;
  78.     }
  79.  
  80.     /// alegem coada din care fac parte nodurile noii multimi
  81.     if (a == -1 || st[1] == dr[1])
  82.         g = 1;
  83.     else
  84.         g = 0;
  85.  
  86.     s[h] += dr[g]; /// noua multime are "dr[g]" noduri
  87.     if (a != -1) { /// reactualizam cardinalitatea multimii mari
  88.         if (g == 0)
  89.             s[u[b]] -= dr[g];
  90.         else
  91.             s[u[a]] -= dr[g];
  92.     }
  93.  
  94.     for (int i = 0; i < dr[g]; i++)
  95.         u[q[g][i]] = h; /// noua multime din care fac parte nodurile din coada este "h"
  96. }
  97.  
  98. inline void scoate(int x, int y, int &best) { /// subarborele lui "x (y)" isi declara independenta fata de de cel al lui "y (x)" (in functie de care este mai mic)
  99.     s[0]++; /// se creeaza o noua multime
  100.     bfs(x, y, s[0]); /// reactualizam multimile dupa eliminarea teoretica muchiei intre x si y
  101.  
  102.     /// reactualizam indicele multimii cu potentialul de a fi prea mare
  103.     if (s[u[x]] > s[best])
  104.         best = u[x];
  105.     if (s[u[y]] > s[best])
  106.         best = u[y];
  107. }
  108.  
  109. inline void adauga(int x, int y, int z, int k, int &ind, int &ans) {
  110.     int multime = u[x], nod = y; /// nodurile din subarborele lui "y" urmeaza sa fie anuntate ca apartin multimii din care face parte "x"
  111.     if (s[u[y]] > s[multime]) { /// sau invers, in caz ca subarborele lui "x" are mai putine elemente
  112.         multime = u[y];
  113.         nod = x;
  114.     }
  115.  
  116.     s[u[nod]] = 0; /// multimea urmeaza sa fie goala
  117.     bfs(-1, nod, multime); /// nodurile "u[nod]" isi cunosc noua multime din care fac parte
  118.  
  119.     /// inseram noul vecin in listele de adiacenta ale nodurilor
  120.     baga(x, y);
  121.     baga(y, x);
  122.  
  123.     while (s[multime] >= k) { /// daca e vreo multime care sa aiba mai mult de "k" noduri, aceea este "multime"
  124.         ans = std::min(ans, z - m[ind].z); /// actualizam raspunsul
  125.         scoate(m[ind].x, m[ind].y, multime); /// scoatem muchia de cost minim care se afla in padure
  126.         ind++; /// avem o noua muchie de cost minim
  127.     }
  128. }
  129.  
  130. int main() {
  131.     int n, k;
  132.     fscanf(fin, "%d%d", &n, &k);
  133.  
  134.     int ind = 1; /// retinem indicele muchiei de cost minim care se afla in graf
  135.     int ans = INF; /// initializam raspunsul cu INF, deoarece se urmareste minimizarea acestuia
  136.     for (int i = 1; i <= n; i++) {
  137.         u[i] = i; /// i se afla initial in multimea care ii poarta numele
  138.         s[i] = 1; /// multimea "i" are un singur element acum
  139.     }
  140.     s[0] = n; /// am creat "n" multimi
  141.  
  142.     for (int i = 1; i < n; i++) {
  143.         fscanf(fin, "%d%d%d", &m[i].x, &m[i].y, &m[i].z);
  144.         adauga(m[i].x, m[i].y, m[i].z, k, ind, ans); /// adaugam muchiile in ordine crescatoare dupa cost
  145.     }
  146.  
  147.     fprintf(fout, "%d\n", ans); /// obtinuram raspunsul
  148.  
  149.     fclose(fin);
  150.     fclose(fout);
  151.     return 0;
  152. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement