Sets - Забони барномасозии C++ барои барномасозии рақобатӣ
Week 11Sets, Maps, Multisets and Key-Based Data Processing
Sets
A set keeps each value once and in order: insert, size and walking in order, count and find, erase, the nearest values with lower_bound and upper_bound, and one set of positions for each letter.
Назария
Дарси 1 аз 7
Хониш: 19 дақиқа
Саволҳо: 6
A vector remembers everything: every value, in the order it came, duplicates
included. Often a problem needs less than that, and needs it fast. Which
values have appeared? Is this one of them? Searching a vector of 200 000 values
for each of 200 000 questions takes 40 billion steps. A set answers each
question in about 18.
A set keeps each value once, in order
A set follows two rules, and keeps them by itself:
No duplicates. Inserting a value that is already there changes nothing.
Always sorted. The values are kept in increasing order, whatever order
they arrive in. You never call sort.
s.size() is the number of values in the set — so after inserting everything,
it is the number of different values. s.empty() says whether the set has
nothing in it. Step through six inserts and watch where each value lands:
A range-for over a set visits its values from smallest to largest, the same
loop you use for a vector. That is all this problem needs:
The first line holds n, the second n whole numbers. Print how many
different values there are, then those values in increasing order.
For the input 7 and 50 20 50 40 20 10 50 it prints
Four different values, already sorted, and no duplicates to skip. A
set<string> works the same way and keeps its words in dictionary order — the
order < gives strings, character by character.
Is it there? count and find
Two ways to ask whether x is in the set, without changing it:
s.count(x) is 1 if x is there and 0 if not — a set never holds two
copies, so nothing else is possible.
s.find(x) gives the position of x in the set: an iterator. Write
*it to read the value at that position. If x is missing, find returns
s.end() — a position just past the last value, which means "not found".
Most of the time count is all you need, as in this problem:
The first line holds n, the second the n names on a guest list. Then
come q and q names of people at the door. For each of them, print YES
if the name is on the list and NO if it isn't.
Put the list into a set once; then each person at the door is one count:
With zara ali tim bek on the list and the people bek dana ali at the door,
it prints YES, NO, YES.
Removing a value: erase
s.erase(x) removes x from the set. If x isn't there, nothing happens — no
error.
A set has no indices: s[0] doesn't compile. The smallest value is
*s.begin() — the value at the first position — and the largest is
*s.rbegin(), the first position counting from the end. Both need a set that
isn't empty.
The nearest values: lower_bound and upper_bound
Because a set is sorted, it can answer "what is the nearest value to x?" just
as fast:
s.lower_bound(x) — the first value ≥ x;
s.upper_bound(x) — the first value > x.
Both return a position, and s.end() if there is no such value. For
s = {10, 20, 30, 40, 50}:
x
*s.lower_bound(x)
*s.upper_bound(x)
25
30
30
30
30
40
5
10
10
50
50
end() — nothing is > 50
Here is a problem that needs the nearest value on both sides:
n bus stops stand along a road, each at a whole-number distance from its
start. For each of q points x, print the next stop — the first one at x
or after it — and the previous stop — the last one at x or before it. Print
- where there is no such stop.
The next stop is lower_bound(x). The previous one is the largest value
≤ x, and no function gives it directly. Take upper_bound(x) — the first
stop past x — and step one position back with it--. Only one thing can go
wrong: if upper_bound is already the very first position, there is nothing
before it.
With stops at 40 10 30 50 20 and the questions 25 50 5 it prints
Write s.lower_bound(x), not lower_bound(s.begin(), s.end(), x). The second
compiles too, but it walks through the set one value at a time — as slow as
searching a vector.
Now put it all together. Guests arrive at a club whose door is guarded by a set:
The set bouncerсанҷида бин!
One set per letter
A set doesn't have to hold the values themselves — it can hold where they
are. Take this problem:
The first line holds a string of lowercase letters, the second q. Each of
the next q lines holds a range l r, with positions counted from 1. For each
range, print the different letters between positions l and r, in
alphabetical order.
Walking through every position of a long range, again and again, is slow.
Instead, keep one set of positions for each letter. Then one lower_bound per
letter answers "does this letter appear between l and r?": its first
position at l or after it must exist and be at most r.
For mississippi and the ranges 1 4 and 5 11 it prints ims and ips.
vector<set<int>> pos(26) is 26 empty sets, one per letter, and s[i] - 'a'
picks the right one, just as in Week 5.
Some problems also change the string. If the letter at position p becomes
the letter c, move p from the old letter's set to the new one's:
What it costs
A set keeps its values in a balanced tree, so insert, erase, count,
find, lower_bound and upper_bound each take about log₂ n steps — 18
for 200 000 values. Walking all of it takes n steps.
vector<int>
set<int>
Duplicates
kept
dropped
Order
as inserted
always increasing
a[i]
one step
not available
Is x there?
look at every value: n steps
count / find: about log₂ n
Nearest value to x
sort first, then search
lower_bound / upper_bound: about log₂ n
Add or remove a value
at the end: one step; in the middle: up to n
about log₂ n, anywhere
Check your understanding
Did you know?
Set was once the English word with the most meanings. In the 1989 edition of
the Oxford English Dictionary its entry listed about 430 senses and ran to some
60 000 words. Its programming meaning — a collection with no repeats — comes
from mathematics, where Georg Cantor made sets the basis of his work in the
1870s.
set<int> s; // an empty set of intss.insert(40);s.insert(10);s.insert(40); // 40 is already there: nothing happenss.insert(25); // s is now {10, 25, 40}cout << s.size(); // 3
худро санҷ1 хол
An empty set<int> s gets s.insert(5); s.insert(3); s.insert(5); s.insert(1); s.insert(3);. What is s.size()?
Барои ҷавоб додан ва нигоҳ доштани пешрафт ворид шавед.Ворид шудан
худро санҷ1 хол
After s.insert(7) is run twice on a set<int> s, s.count(7) is 2.
Барои ҷавоб додан ва нигоҳ доштани пешрафт ворид шавед.Ворид шудан
худро санҷ1 хол
s is the set {10, 20, 30, 40}. What are *s.lower_bound(20) and *s.upper_bound(20)?
Як ҷавобро интихоб кунед
Барои ҷавоб додан ва нигоҳ доштани пешрафт ворид шавед.Ворид шудан
худро санҷ1 хол
s is the set {10, 20, 30, 40}. What does this print?
Барои ҷавоб додан ва нигоҳ доштани пешрафт ворид шавед.Ворид шудан
худро санҷ1 хол
What does this print?
Як ҷавобро интихоб кунед
Барои ҷавоб додан ва нигоҳ доштани пешрафт ворид шавед.Ворид шудан
худро санҷ1 хол
How do you get the smallest value of a non-empty set<int> s?
Як ҷавобро интихоб кунед
Барои ҷавоб додан ва нигоҳ доштани пешрафт ворид шавед.Ворид шудан
4
10 20 40 50
30 20
50 50
10 -
#include <bits/stdc++.h>using namespace std;int main(){ ios_base::sync_with_stdio(false); cin.tie(NULL); int n; cin >> n; set<int> s; for(int i = 0; i < n; i++){ int x; cin >> x; s.insert(x); // a value that is already there is not added again} cout << s.size()<< "\n"; // how many different values for(int x : s){ // smallest to largest cout << x << " ";} cout << "\n"; return 0;}
auto it = s.find(25); // auto: let the compiler work out the typeif(it != s.end()){ cout << *it << " is here";}
#include <bits/stdc++.h>using namespace std;int main(){ ios_base::sync_with_stdio(false); cin.tie(NULL); int n; cin >> n; set<string> invited; for(int i = 0; i < n; i++){ string name; cin >> name; invited.insert(name);} int q; cin >> q; for(int i = 0; i < q; i++){ string name; cin >> name; if(invited.count(name)){ // 1 if the name is in the set, 0 if not cout << "YES"<< "\n";} else{ cout << "NO"<< "\n";}} return 0;}
set<int> s ={10, 25, 40};s.erase(25); // {10, 40}s.erase(99); // not there: still {10, 40}
#include <bits/stdc++.h>using namespace std;int main(){ ios_base::sync_with_stdio(false); cin.tie(NULL); int n; cin >> n; set<int> stops; // where the bus stops are along the road for(int i = 0; i < n; i++){ int x; cin >> x; stops.insert(x);} int q; cin >> q; for(int i = 0; i < q; i++){ int x; cin >> x; auto it = stops.lower_bound(x); // the first stop at x or after it if(it == stops.end()){ cout << "-"; // every stop is before x} else{ cout << *it;} cout << " "; it = stops.upper_bound(x); // the first stop after x if(it == stops.begin()){ cout << "-"; // that is the very first stop: none at x or before} else{ it--; // one step back: the last stop at x or before cout << *it;} cout << "\n";} return 0;}
#include <bits/stdc++.h>using namespace std;int main(){ ios_base::sync_with_stdio(false); cin.tie(NULL); string s; cin >> s; vector<set<int>> pos(26); // pos[0]: where the a's are, pos[1]: the b's, ... for(int i = 0; i <(int)s.size(); i++){ pos[s[i] - 'a'].insert(i + 1); // positions counted from 1} int q; cin >> q; for(int i = 0; i < q; i++){ int l, r; cin >> l >> r; for(int c = 0; c < 26; c++){ auto it = pos[c].lower_bound(l); // this letter's first position at l or after if(it != pos[c].end() && *it <= r){ cout <<(char)('a' + c); // it is inside [l, r]}} cout << "\n";} return 0;}
pos[s[p - 1] - 'a'].erase(p); // the old letter leaves position ps[p - 1] = c;pos[c - 'a'].insert(p); // the new letter arrives
auto it = s.upper_bound(35);it--;cout << *it;
set<int> s ={30, 10, 20, 10};for(int x : s){ cout << x << " ";}