Skip to content

Commit 8aeea1d

Browse files
Add files via upload
1 parent 1af3ab5 commit 8aeea1d

File tree

1 file changed

+204
-0
lines changed

1 file changed

+204
-0
lines changed
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
2+
Let us say we have an array of $1$�s and $ 0$�s. How do we find the sum of intervals of this array and support quick updates ?
3+
Segment tree. This is just a simple sum tree. Now, let us reduce the above problem to this question.
4+
5+
6+
7+
(Firstly, observe that the number of distinct elements in the range $[L, R]$ is equal to the number of elements who�s last occurence $[1, R]$ is $>= L$. )
8+
9+
10+
11+
Let us maintain an array of length $ N$.
12+
13+
$A[i] = 1$, if position $i$ is the last occurence of some element.
14+
15+
$A[i] = 0$, otherwise.
16+
17+
Now, one by one, we will insert elements into this tree.
18+
19+
20+
Let us say the current element is $v$
21+
We make the $A[L[v]] = 0$ and $A[i] = 1$
22+
23+
Where$ L[v] $represents the last occurence of $v $
24+
25+
Prior to this insertion.
26+
27+
Update the sum tree accordingly.
28+
29+
30+
31+
Now, check if any query ends at $i$.
32+
33+
For all queries with $R = i$
34+
35+
There is sufficient information to answer it.
36+
37+
We know the last occurence of every element upto $R$.
38+
We just need to check how many of them are after $L$
39+
40+
41+
Since, the array $A$ holds $1$ if it is the last occurence, we just find the sum $[L, R]$
42+
43+
The number of $1$�s in that range gives us the number of elements who�s last occurence $>= L$
44+
45+
46+
47+
Now, how do we efficiently get all queries with $R = i $efficiently without degrading to $O(NQ)$
48+
49+
50+
51+
Treat everything as an event.
52+
53+
There are two kinds of events - Sum events and Query events.
54+
55+
56+
For insertion event, we need ---> Position, value.
57+
58+
59+
For query event, we need ---> Left, right, query_no.
60+
61+
62+
Sort all the events by the following criteria ---> (Position, for insertion), (Right, for queries)
63+
64+
65+
This is $O((N + Q) log(N + Q))$
66+
67+
Then go through the events one by one.
68+
69+
70+
If it�s an insertion, set $A[L[v]] = 0$ and $A[i] = 1$
71+
72+
with appropriate updates on the sum tree.
73+
74+
75+
76+
If it�s a query event, return the number of $1$�s (sum) in the range $[L, R]$
77+
78+
----------------------------------------------------------------------------
79+
80+
struct info
81+
{
82+
int end;
83+
int type;
84+
int position, value;
85+
int left, right, query_no;
86+
87+
info(){ end = type = left = right = query_no = position = -1; }
88+
};
89+
90+
int compare_ends(const info &A, const info &B)
91+
{
92+
if(A.end < B.end)
93+
return true;
94+
else if(A.end == B.end)
95+
return (A.type == INSERTION);
96+
97+
return false;
98+
}
99+
100+
void insert(int n, int left, int right, int position, int position_type)
101+
{
102+
if(right < position || position < left)
103+
return;
104+
105+
if(left == right)
106+
{
107+
if(position_type == OLD_LAST_OCCURENCE)
108+
tree[n] = 0;
109+
else if(position_type == NEW_LAST_OCCURENCE)
110+
tree[n] = 1;
111+
112+
return;
113+
}
114+
115+
int mid = (left + right) >> 1;
116+
117+
if(position <= mid)
118+
insert(LEFT(n), left, mid, position, position_type);
119+
else if(position > mid)
120+
insert(RIGHT(n), mid + 1, right, position, position_type);
121+
122+
tree[n] = tree[LEFT(n)] + tree[RIGHT(n)];
123+
}
124+
125+
int query(int n, int left, int right, int query_left, int query_right)
126+
{
127+
if(query_right < left || right < query_left)
128+
return 0;
129+
130+
if(query_left <= left && right <= query_right)
131+
return tree[n];
132+
133+
int mid = (left + right) >> 1;
134+
135+
int left_answer = query(LEFT(n), left, mid, query_left, query_right);
136+
int right_answer = query(RIGHT(n), mid + 1, right, query_left, query_right);
137+
138+
return (left_answer + right_answer);
139+
}
140+
141+
int main()
142+
{
143+
memset(tree, 0, sizeof(tree));
144+
145+
vector <info> event;
146+
147+
int no_of_elements;
148+
scanf("%d", &no_of_elements);
149+
for(int i = 1; i <= no_of_elements; i++)
150+
{
151+
info current_event;
152+
current_event.type = INSERTION;
153+
current_event.end = current_event.position = i;
154+
scanf("%d", &current_event.value);
155+
156+
event.push_back(current_event);
157+
}
158+
159+
int no_of_queries;
160+
scanf("%d", &no_of_queries);
161+
for(int i = 1; i <= no_of_queries; i++)
162+
{
163+
info current_event;
164+
current_event.type = QUERY;
165+
166+
scanf("%d %d", &current_event.left, &current_event.right);
167+
current_event.end = current_event.right;
168+
current_event.query_no = i;
169+
170+
event.push_back(current_event);
171+
}
172+
173+
sort(all(event), compare_ends);
174+
175+
int no_of_events = no_of_elements + no_of_queries;
176+
177+
map <int, int> last_occurence;
178+
vector <int> answer(no_of_queries + 1);
179+
180+
for(int i = 0; i < no_of_events; i++)
181+
{
182+
if(event[i].type == INSERTION)
183+
{
184+
int element = event[i].value;
185+
186+
if(last_occurence.count(element) == 1)
187+
{
188+
insert(1, 1, no_of_elements, last_occurence[element], OLD_LAST_OCCURENCE);
189+
}
190+
191+
insert(1, 1, no_of_elements, event[i].position, NEW_LAST_OCCURENCE);
192+
last_occurence[element] = event[i].position;
193+
}
194+
else if(event[i].type == QUERY)
195+
{
196+
answer[event[i].query_no] = query(1, 1, no_of_elements, event[i].left, event[i].right);
197+
}
198+
}
199+
200+
for(int i = 1; i <= no_of_queries; i++)
201+
printf("%d\n", answer[i]);
202+
203+
return 0;
204+
}

0 commit comments

Comments
 (0)