Just Update and Print the array
|
You are given a 1-indexed array of size N. Initially, all elements of the array are zeros. You need to performU updates to the array.
Each Update asks you to add 1 to the elements of the array at the indices specified by 'ax+b' for all non-negative integers x, where a and b are positive integers which specify an update query.
After performing all the updates to the array, print the array with every entry separated by space.
Input
First Line of the input contains 2 space separated integers N, U.
Each of the next U lines contains 2 space-separated integers: a and b, specifying an update.
Output
Output the array in a single line after all updates.
Constraints
- 1 ≤ N ≤ 105
- 1 ≤ a, b ≤ N
- 1 ≤ U ≤ 2*105
Example
Input: 7 4 1 3 7 7 7 3 2 2 Output: 0 1 2 2 1 2 2
Explanation
Array after first update : [0,0,1,1,1,1,1]
Array after second update : [0,0,1,1,1,1,2]
Array after third update : [0,0,2,1,1,1,2]
Array after fourth update : [0,1,2,2,1,2,2]
Array after second update : [0,0,1,1,1,1,2]
Array after third update : [0,0,2,1,1,1,2]
Array after fourth update : [0,1,2,2,1,2,2]
=====================================EDITORIAL=========================================
DIFFICULTY:
Medium
PREREQUISITES:
sqrt decomposition, offline range sums
PROBLEM:
Given an array , all initially zeros. You need to perform updates to the array, where each update asks you to increment the array at the indices for all integers . What is the resulting array?
QUICK EXPLANATION:
Perform all updates where manually. Store all other updates (i.e. those with ).
Let's fix an and perform all updates with this simultaneously. To do so:
- Compute , where is the number of updates with .
- Compute where for and for .
- Finally, increment with for all .
EXPLANATION:
Obviously, brute-force will not work because the worst case complexity of each update is , so the overall worst-case running time becomes .
The problem is a lot easier though if the updates all have . In that case, we're only dealing with range sum updates, which are famously easy to solve with a segment tree. In fact, we don't need a segment tree at all! A much simpler algorithm exists for the offline version of the problem, where it is assumed that all updates are known beforehand:
- Compute , where is the number of updates with . This can be done with a linear scan among all updates .
- Compute , where is the amount to increment to . is easily seen to be , so can easily be calculated using the recurrence for with base case for .
- Finally, increment with for all .
For example, suppose and we want to process the queries , , , , and . We will have:
One can check that is indeed the value to be added to for all , and that for .
Now, what about the updates ? Well, we don't know yet. But, we can in fact use a similar algorithm as above for the case : there are two types of updates of the form — those with even and and odd — and we can use the algorithm above separately for the even and odd ones. And in fact, we can combine both the even and odd half into a single unified algorithm: Just replace the recurrence with . The running time is still overall.
Actually, we can perform a similar algorithm for all the other s! Each particular takes to process. So we now have an alternative algorithm: group the updates according to , then perform the algorithm above for every . Unfortunately, this algorithm is also slow. Each time we perform the algorithm above we incur a running time of , giving an overall running time of , which is still too slow.
But what if we only perform the algorithm above for some s? For updates with other s, we can simply perform the update manually. Let's say we perform the algorithm above only for small , i.e. those that are for some (still unknown) value . Since we perform the algorithm above only times, and the running time of all other updates is at worst , this gives us an overall running time of . If we choose as, say, , then the overall algorithm becomes , which is fast enough to pass the time limit!
Keep in mind though that you have a choice of constant in the " notation" so practically it's still up to you to choose really. The optimal constant depends on your implementation and you can try to find it via trial-and-error / ternary search. We suggest choosing not too far from though.
Theoretically better parameter
Notice above that we chose as without really thinking about it that much. It's just pure intuition. Here we'll choose a better parameter to get a theoretically better running time.
The running time is , and we want to make the running time as small as possible. Since decreases and decreases as increases, it's best to choose that will make them equal to make their sum as small as possible (at least in terms of notation). Thus, we want . Thus, in fact the better choice would be , NOT , and the running time we get . Note that this running time is better than in almost all cases!
Note that we said and not just , because it's possible that , in which case iterating through all updates dominates the running time.
This doesn't really matter that much in terms of the contest, but it's interesting nonetheless.
Time Complexity:
or
=======================================CODE===========================================
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> p;
#define getcx getchar_unlocked
inline void inp( int &n )//fast input function
{
n=0;
int ch=getcx();int sign=1;
while( ch < '0' || ch > '9' ){if(ch=='-')sign=-1; ch=getcx();}
while( ch >= '0' && ch <= '9' )
n = (n<<3)+(n<<1) + ch-'0', ch=getcx();
n=n*sign;
}
int ans[100005],n,u;
p arr[200005];
void update2(int st,int ct)
{
int i,x;
int a=arr[st].first;
for(i=0;i<ct;i++,st++)
{
int b=arr[st].second;
for(x=0;a*x+b<=n;x++)
{
ans[a*x+b]++;
}
}
}
void update1(int st,int ct)
{
int i,j;
// creating C[] and D[] array as mentioned in editoral..
int c[n+1];
int d[n+1];
int a=arr[st].first;
memset(c,0,sizeof(c));
memset(d,0,sizeof(d));
for(i=st;i<st+ct;i++)
{
c[arr[i].second]++;
}
for(i=1;i<=a;i++)
d[i]=c[i];
for(;i<=n;i++)
d[i]=c[i]+d[i-a];
for(i=1;i<=n;i++)// updating
ans[i]+=d[i];
}
int main()
{
ios_base::sync_with_stdio(false);
int i,j,k;
inp(n);inp(u);
for(i=0;i<u;i++)
{
inp(arr[i].first);
inp(arr[i].second);
}
sort(arr,arr+u);
i=0;
int sq=int(sqrt(n));
while(i<u)
{
int count=1;
while(arr[i].first==arr[i+1].first)
{
count++;
i++;
}
int tempa=arr[i].first;
if(tempa<=sq)
update1(i-count+1,count);
else
update2(i-count+1,count);
i++;
}
for(i=1;i<=n;i++)
cout<<ans[i]<<" ";
}
No comments:
Post a Comment