Γραμμική λύση στο conflicts (35 Γ'φαση 3ο θέμα). #260
doublemidi
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Βρήκα$Ο(n)$ λύση στο πρόβλημα που δεν χρειάζεται κανέναν περίπλοκο αλγόριθμο και ήθελα να το μοιραστώ, αφού την μέρα του διαγωνισμού συζητήθηκαν μονο λύσεις με $Ο(nlogn)$ και $O(nlog^2(n))$ χρόνο που ήθελαν small-to-large ή segment trees. Επειδή δεν υπάρχει λύση στο https://pdp-archive.github.io/ θα εξηγήσω την λύση μου από το μηδέν:
Αφού η ισχύς του$u$ είναι το άθροισμα των $f_w$ για κάθε $w$ στο υπόδεντρο του $u$ , μπορούμε εύκολα να το υπολογίσουμε με dp on tree.$A_u$ την ισχύ του $u$ .$u$ , μας ζητάται να βρούμε το πλήθος nodes $w$ με $A_u == A_w$ έτσι ώστε να είναι το $u$ ούτε πρόγονος ούτε απόγονος του $w$ .$ans_u$ το πλήθος αυτό.
Θέτω
Για κάθε node
Θέτω
Προφανώς$ans_u == all_u - up_u - down_u$ .$all_u$ :$Ο(n)$ .
Λύνουμε το
Λύνεται αρκετά εύκολα, με ένα frequency table (με std::unordered_map). Αυτό θέλει χρόνο
Λύνουμε το$up_u$ :$dfs$ , για κάθε node $u$ που θα επισκέπτεται η $dfs$ θα κρατάμε ένα frequency table που θα έχει τα nodes στο path απο το $u$ στο root. Έτσι υπολογίζεται το $up_u$ . Αυτό θέλει χρόνο $O(n)$ .
Με μία
Λύνουμε το$down_u$ :$u$ , S_u, και end time Ε_u), ένα υπόδεντρο, γίνεται υποπίνακας. Το μέγεθος του πινακα ET είναι $\leq n$ Έτσι, πρέπει να βρούμε το πλήθος nodes $w$ στον υποπίνακα $[S_u, E_u)$ με $A_u == A_w$ . Με την ιδέα του prefix count, αρκεί να βρούμε το πλήθος στο $[0, S_u)$ και στο $[0, Ε_u)$ και να τα αφαιρέσουμε. Για να απαντήσουμε αυτά τα prefix sum "queries" αυτά, θα χτίσουμε occurence table για κάθε διαφορετική τιμή του $A$ (πάλι με std::unordered_map). Το occurence table θα έχει για κάθε εμφάνιση τιμής, το index στο οποίο εμφανίζεται σε αύξουσα σειρά. Αυτό γίνεται σε $O(n)$ αν προσθέτουμε τις τιμές με την σειρά του euler tour.$O(logn)$ , για τελική πολιπλοκότητα $O(nlogn)$ . Πώς γίνεται να το ρίξουμε όμως σε γραμμικό;
Αυτό είναι το πιο δύσκολο κομμάτι. Κάνοντας ένα euler tour στο δέντρο (αποκαλούμε τον πίνακα ET, με start time του
Με μία binary search μπορούμε να απαντήσουμε κάθε query σε
Με την ιδέα της counting sort, μπορούμε να ταξινομίσουμε τα queries ως προς το$i$ , όπου τα queries είναι της μορφής $[0, i]$ με $A_u == x$ . Αυτό μπορούμε να το κάνουμε, αφού τα $i$ δεν ξεπερνάνε το $n$ $O(n)$ χρόνο, αφού σε κάθε σημείο
Αφού τα queries έχουν πλέον μονοτονία, μπορούμε για κάθε occurence table να κρατάμε και ένα pointer που θα αντιστοιχεί στο τελευταίο index που είχε χρειαστεί σε προηγούμενο query (αρχίζει στην αρχή του table) και θα το προχωράμε δεξιά με γραμμική αναζήτηση μέχρι να φτάσει το σημείο που του ζητάται στο query. Αυτή η διαδικασία παίρνει
του occurence table μπαίνουμε το πολύ μία φορα, και βγαίνουμε το πολύ μία φορά.
Συνολικά ο αλγόριθμος παίρνει$Ο(n)$ χρόνο με την κρυμμένη σταθερά του std::unordered_map.
Είμαι ανοιχτός σε οποιαδήποτε απορία για την λύση, αλλα και ιδέες και λύσεις για το πρόβλημα!
Ο κώδικας (περνάει όλα τα testcases στον https://pdp-archive.github.io/ ):
Beta Was this translation helpful? Give feedback.
All reactions