Module: Mo-Algorithmus


Problem

1 /4


Theory Click to read/hide

Algorithmen Mo ist in der Lage, auf Anträge auf Kürzungen reagieren nicht ersetzbar massiv Offline (i meine, zuerst alle Fragen kennen und dann beantworten).

Der Vorteil des Mo ' s-Algorithmus, verglichen mit anderen Ansätzen, ist, dass es oft ermöglicht, die komplexen Funktionen zu berücksichtigen, die oft unklar sind, wie die Wälder von Clips oder andere Datenstrukturen zu unterstützen. Der Algorithmus selbst ist ganz einfach.
Die Lektion ist, dass es wahrscheinlich ist, dass es eine asymptotisch zeiteffizientere Weise, zum Beispiel durch anhaltendes Holz von Schnitten, aber reale Gewinne im Laufe der Zeit sind wahrscheinlich nicht die Kosten des Schreibens eines komplexeren Codes zu kompensieren.
Wir unterschreiben den Algorithmus Mo asymptotisch später.

Beschreiben Sie den Algorithmus selbst:

Plötzlich (d.h. nicht in der Tat) brechen wir die vorhandene Masse auf S-Zellblöcken. Dies ist der erste Block mit Komponenten mit Indexen [0;S-1], der zweite Block mit Elementen mit Indizes [S; 2S-1], etc. Der letzte Block ist wahrscheinlich weniger als S-Elemente enthalten, aber er ist nicht beängstigend.

Wir quälen die bestehenden Anfragen weiter wie folgt: zuerst in Höhe der Anzahl der Einheit, in der sich die linke Grenze des Antrags befindet und wenn sie auf der Höhe der rechten Grenze des Antrags gleich sind.

Wir werden nun Anfragen auf diese Weise bearbeiten und die Grenzen von der aktuellen Anfrage zum nächsten bewegen.
Es geht so:
Zunächst betrachten wir die Antwort auf die erste Anfrage oder wir können mit neutralen Werten beginnen, d.h. vom Ausgang. Jetzt haben wir einige aktuelle Grenzen, eine Antwort auf die Begrenzung dieser Grenzen, und vielleicht eine Batterie, mit der wir den Wert der Funktion betrachten (z.B. Hilfsmasse mit der Anzahl der Elemente auf diesem Schnitt oder so weiter).
Wir werden dann von dem aktuellen Schnitt zum nächsten durch einzelne Änderungen der aktuellen Grenzen ziehen.
Ich meine, wenn die neue rechte Linie richtig ist als die aktuelle, erweitern wir das aktuelle Sub-Office, indem wir neu rechts hinzufügen und die Funktion zählen, solange die aktuelle rechte Grenze nicht neu ist.
Ist die neue rechte Linie linker als die aktuelle, so wird die Stromabschaltung durch die Entfernung der alten Rechten errichtet. Genau wie die linke Linie.
Es wird empfohlen, die Schnitte zuerst zu verlängern und dann zu quetschen, um zu vermeiden, versehentlich den Schnitt zu extrahieren.

Es ist also nur erforderlich, ein Element aus dem Masseende zu addieren/zuordnen und dann die Funktion neu zu berechnen, was genau das macht. Mo ' s Algorithmus geeignet und bequem für die Berechnung komplexer Anfragen für Schnitte.

Wofür funktioniert das?

Wählen wir S gleich sqrt(N), wo N die Länge der Masse ist. Also haben wir sqrt(N) Blöcke auf sqrt(N) Elemente in jedem.
Betrachten Sie die Anzahl der Grenzbewegungen:
Werden die rechtwinkligen Grenzen gestrafft, wird der rechte Marker nicht mehr als N Bewegungen ausführen. Aber wenn man die linke Linie zum nächsten Block bewegt, wird die Ordnung der rechten Grenzen verschärft. Blocks sqrt(N) Zeug, so dass die gesamte richtige Linie entfernt werden.- Ja. Eins.
Bei jedem Übergang zu einer neuen Anforderung kann sich die linke Begrenzung entlang eines ganzen Blocks, d.h. des Elements sqrt(N) bewegen. Bei der Umstellung auf den neuen Block, jede Anzahl von Elementen (einige Blöcke können nicht gefragt werden), aber die Gesamtzahl für alle Kreuzungen ist nicht mehr als N von Elementen (wie wir die Anforderungen des erhöhten Blocks rationalisiert haben). Auf dieser Grundlage wird sich die linke Grenze verschieben- Ja. wobei M die Anzahl der Anträge ist.
Angesichts der Art der Anträge, Mos Gesamtalgorithmus funktioniert für C)wobei f(x) die Zeit ist, für die Sie beim Hinzufügen/Aus eines Elements die notwendige Funktion abschließen.

Anwendungsbeispiel:

In dieser Hinsicht werden wir nur eine ganze Zahl von Nichttarifen betrachten.
Dun ist eine Masse von n Meißel. Wir müssen auf m Anfragen für mex-a im Unterabschnitt antworten. MexmInimumex Kapitel(geschlossen) - Mehrere Zahlen Operation, die die Mindestnummer zurückgibt, die nicht in dieser Vielzahl ist. Beispiele:
({0, 1, 2}) = 3.
({0, 1, 3}) = 2.
({1, 2, 3}) = 0.
({}) = 0.

Auf der Suche nach Zahlen können wie folgt sein: Wir haben eine geordnete Anzahl von Zahlen, die nicht in unserem Bereich sind. Zunächst sind es alle Zahlen von 0 bis n+1 (mex viele nicht übersteigen seine Größe+1). Es ist ferner möglich, die Zahlen aus der Masse hinzuzufügen und aus den vielen fehlenden zu entfernen. Wenn wir alle Zahlen hinzufügen, wird die Mex bei vielen Vermissten die niedrigste sein. Wir können auch mex aktualisieren, wenn die Zahlen entfernt werden. Um dies zu tun, müssen wir viele Zahlen halten, um zu verstehen, wenn wir neue hinzufügten und wenn wir die letzte gelöscht haben.

So können wir mex Multiples zählen, wenn eine Nummer hinzugefügt oder entfernt wird, die ausreicht, um anzuwenden Mos Algorithmus. Betrieb der Zugabe und Entfernung einer Zahl- Ja. Zeit, so wird die allgemeine Asymptomie gleich sein.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Der Code wird unten dargestellt:

/ Struktur für Anfragen
struct abfragen {
/ Linke Grenze, rechte Grenze und Anfragenummer
int l, r, num;
?

/ Größe des Blocks
// Anstelle eines fairen sqrt(n) werden wir es als Konstante aufzeichnen (320 ~= sqrt(100000)
/ Dies könnte gehandhabt werden, wodurch das Programm beschleunigt werden kann
const int S = 320;

/ Komparator zur Sortierung von Anfragen
bool cmp(const query input a, const query input b) {
wenn (a.l / S!= b.l / S)
zurück a.l / S À b.l / S; / / , Erstklassig auf der Höhe des linken Begrenzungsblocks
andere
zurück a.r PER b.r; / mit Gleichheit, klassifizieren auf der Höhe der rechten Grenze
♪

const int MAXN = (int)1e+5 + 5;

/ Referenz
Int arr[MAXN];

/ Struktur zum Sammeln von Antworten auf Anfragen
struktiver Zustand {
/ Stromabschaltgrenze
int l, r;

// Viele Zahlen nicht im aktuellen Unterabschnitt
Menge  abwesend;

/ Masse gespeichert in aktuellem Sublet
int cnt[MAXN];

Zustand() {
// Es wird zunächst ein ausgegrabenes Sublet geben, d.h. leere Lose
l = 0;
r = -1;

für (int i = 0; i À MAXN; i+++) {
cnt[i] = 0; // in leeren Losen, die Anzahl aller Zahlen gleich Null
absent.insert(i); /, jedoch sind alle Zahlen nicht verfügbar
♪
♪

/ Addition der Nummer im Sublet
/ Anzahl erhöhen
// Wenn es keine Zahlen gab, erschien es, so sollte es von den vielen vermissten entfernt werden.
Leer add(int x) {
wenn (cnt[x)
absent.erase(x);
cnt[x]+++;
♪

/ Entfernung
/ Abnahmenummer
/ Wenn es null ist, ist die Nummer weg, also muss sie vielen vermissten hinzugefügt werden.
Leer entfernen(int x) {
cnt[x]-
wenn (cnt[x)
absent.insert(x);
♪

Nicht verfügbar {~}
r++;
fügen (arr[r]);
♪

Leer add_left() {~}
l--
fügen(arr[l)
♪

Nichtigkeit rem_right() {~}
Entfernen (arr[r]);
r---
♪

Leere rem_left() {~}
Entfernen (arr[l)
L++;
♪

/ mex Stromschnitt = Mindestzahl in vielen fehlenden
int get_mex() {~}
zurück *absent.begin();
♪
?

int main()
{~}
int n;
cin ventri;

für (int i = 0; i À n; i+++)
cin vent arr[i];

int m;
cin vent m;

Vektor Q(m)
Vektor an(m)
/ Zuerst werden wir alle Fragen kennen und dann beantworten wir jede.
für (int i = 0; i À m; i+++) {
cin versatus q[i].l Teerbestandteil q[i].r;
Q[i].l-; q[i].r--
q[i].num = i; // erinnert an die ursprüngliche Nummer, d.h. sie wird nach Abschreibung geändert
♪
Art(q.begin(), q.end(), cmp);

Zustand s = Zustand();

für (int i = 0; i À m; i+++) {
- Ja.
während (s.r PER q[i].r)
s.add_right();
während (s.l Bestandteil q[i].l)
s.add_left();

/ dann versuchen, zu entfernen
während (s.r Bestandteil q[i].r)
s.rem_right();
während (s.l PER q[i].l)
s.rem_left();

/ Wenn das aktuelle Unterangebot gleich der Anfrage ist, können wir eine Antwort darauf anfordern
ans[q[i].num] = s.get_mex();
♪

für (int i = 0; i À m; i+++)
cout copycat ans[i] Épri ';

Rückkehr 0;
♪

P. S.
Es gibt fortschrittlichere Verwendung von Mo ' s Algorithmus, aber über diese Theorie hinaus, nämlich die Verwendung dieses Algorithmus, unter Berücksichtigung von Anforderungen für die Aktualisierung von Elementen (3-D Algorithmus Mo) und seine Verwendung für Baumabfragen (Mo ' s Algorithmus auf Bäumen).

Euristics (nicht-asymptotische Optimierung) gibt es auch, verbunden mit fortschrittlicheren Abfragen, die Grenzbewegungen zwischen Anfragen reduzieren. Eine einfache Möglichkeit ist, die rechten Blöcke in einem Alter oder in einem Verlust in Abhängigkeit von der Blockzahl zu klassifizieren. Fortgeschrittener - Verwenden Sie die Gilbert-Kurve (detailHier.)

Problem

Du hast ein paar ganze Zahlen bekommen.
Wir müssen auf m &apos antworten; Anträge auf Art " die Anzahl der verschiedenen Nummern des Sublets A vom Element mit Index l zum Element mit r &quot melden; (obwohl der Cutoff enthalten ist, wird das Volumen von der Einheit nummeriert).

Eingabe:
In der ersten Zeile gibt es zwei Zahlen: n = Anzahl der Elemente des Körpers und m = Anzahl der Abfragen (1 À=n, m PO=10)5.)
In der zweiten Zeile sind keine ganzen Zahlen AI - Elemente der Masse (0 Kanal = A)I · 106)
Zusätzlich werden m Zeilen in den beiden Zahlen l und r die Abschaltgrenzen für jede Anforderung angegeben (1 Kanal = l RP = r/n).

Ausgangsdaten:
In der einzigen Linie, durch eine m-Stücklücke - für jede Anforderung die Anzahl der verschiedenen Zahlen auf dem Sublet.

Beispiel:
EingangsdatenAusgangsdaten
7
1 3 1 2 4 1
1 3
5.
3 7
Artikel 4
7
2 1 3 3 1