Problem Link : Problem
This is very common question but hard to answer efficiently.This Problem, I have solved using Two methods.
1. Sqrt-Decomposition
2. Segment Tree with Lazy-Propagation
For First Approach:
* For each block ,cnt which represents which number occur how many time
* an delta Array for each block
For each query, I go-through the block & element,calculate the sum
For each update, Similar approach, cnt array change
Ok this code runs 3.93 sec where Time Limit = 4s.. Not a good solution I guess.
#include <bits/stdc++.h>
using namespace std;
/*------- Constants---- */
#define LL long long
#define ull unsigned long long
#define mod 1000000007
#define MEMSET_INF 63
#define MEM_VAL 1061109567
#define forn(i,n) for( int i=0 ; i < n ; i++ )
#define mp(i,j) make_pair(i,j)
#define lop(i,a,b) for( int i = (a) ; i < (b) ; i++)
#define pb(a) push_back((a))
#define all(x) (x).begin(),(x).end()
#define gc getchar_unlocked
#define PI acos(-1.0)
#define inf 1<<30
#define lc ((n)<<1)
#define rc ((n)<<1 |1)
#define db(x) cout << #x << " -> " << x << endl;
#define DI(n) int n;sc(n)
#define DII(a,b) int a,b;sc(a);sc(b)
#define DIII(a,b,c) int a,b,c;sc(a);sc(b);sc(c)
#define min(a,b) ((a)>(b) ? (b) : (a) )
#define max(a,b) ((a)>(b) ? (a):(b))
/*---- short Cuts ------- */
#define ms(ara_name,value) memset(ara_name,value,sizeof(ara_name))
typedef pair<int, int> ii;
typedef vector<int > vi ;
/*------ template functions ------ */
#ifndef getchar_unlocked
#define getchar_unlocked getchar
#endif
template<class T> inline void sc(T &x){register int c = gc();x = 0;int neg = 0;for(;((c<48 | c>57) && c != '-');c = gc());
if(c=='-') {neg=1;c=gc();}for(;c>47 && c<58;c = gc()) {x = (x<<1) + (x<<3) + c - 48;}if(neg) x=-x;}
template <class T> inline T bigmod(T p,T e,T M){LL ret = 1;for(; e > 0; e >>= 1){if(e & 1) ret = (ret * p) % M;p = (p * p) % M;} return (T)ret;}
template <class T> inline T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template <class T> inline T modinverse(T a,T M){return bigmod(a,M-2,M);}
/*************************** END OF TEMPLATE ****************************/
const int N = 100005;
vector<int> Lucky;
bool L[10005];
void gen(int u)
{
if(u>10000) return;
if(u>0) Lucky.pb(u);
gen(10*u+4);
gen(10*u+7);
}
int A[N];
int block = 320;
int delta[500];
int cnt[500][10005];
void updateElement(int pos,int d)
{
int id = pos/block;
int prv= A[pos];
cnt[id][prv] --;
A[pos] += d;
cnt[id][A[pos]] ++;
}
void updateBlock(int id,int d)
{
delta[id] += d;
}
void update(int lo,int hi,int d)
{
int i;
for(i=lo; i%block&&i<=hi; i ++ ) {
updateElement(i,d);
}
for(; i + block-1 <= hi; i += block) {
updateBlock(i/block,d);
}
for(;i <= hi ; i ++ ) updateElement(i,d);
}
int queryElement(int pos)
{
int id = pos/block;
if(L[A[pos] + delta[id]] ) return 1;
return 0;
}
int queryBlock(int id)
{
int p = delta[id];
int res = 0;
for(int i = 0;i < Lucky.size() ; i++ ) {
int c = Lucky[i] - p;
if(c>0) res += cnt[id][c];
}
return res;
}
int query(int lo,int hi)
{
int i,j;
int res = 0;
for(i=lo;i%block&&i<=hi;i++){
res += queryElement(i);
}
for( ; i + block -1 <= hi ; i+= block){
res += queryBlock(i/block);
}
for(;i<=hi;i++) res += queryElement(i);
return res;
}
int main()
{
gen(0);
sort(all(Lucky));
forn(i,Lucky.size()) L[Lucky[i]] = 1;
DII(n,q);
forn(i,n) sc(A[i]);
forn(i,n){
cnt[i/block][A[i]] ++;
}
int lo,hi;
char t[10];
while(q--){
scanf("%s%d%d",t,&lo,&hi);
lo--,hi--;
if(t[0]=='c'){
int res = query(lo,hi);
printf("%d\n",res);
}
else {
DI(d);
update(lo,hi,d);
}
}
}
With Simple optimization This program can run under 1s.
The optimisation is :
We store The value for each block until The whole block is updated.
Then for quering block, Check , Is the value is already calculated or not.
If calculated then return ans, else calculate manually and store the value
#include <bits/stdc++.h>
using namespace std;
/*------- Constants---- */
#define LL long long
#define ull unsigned long long
#define mod 1000000007
#define MEMSET_INF 63
#define MEM_VAL 1061109567
#define forn(i,n) for( int i=0 ; i < n ; i++ )
#define mp(i,j) make_pair(i,j)
#define lop(i,a,b) for( int i = (a) ; i < (b) ; i++)
#define pb(a) push_back((a))
#define all(x) (x).begin(),(x).end()
#define gc getchar_unlocked
#define PI acos(-1.0)
#define inf 1<<30
#define lc ((n)<<1)
#define rc ((n)<<1 |1)
#define db(x) cout << #x << " -> " << x << endl;
#define DI(n) int n;sc(n)
#define DII(a,b) int a,b;sc(a);sc(b)
#define DIII(a,b,c) int a,b,c;sc(a);sc(b);sc(c)
#define min(a,b) ((a)>(b) ? (b) : (a) )
#define max(a,b) ((a)>(b) ? (a):(b))
/*---- short Cuts ------- */
#define ms(ara_name,value) memset(ara_name,value,sizeof(ara_name))
typedef pair<int, int> ii;
typedef vector<int > vi ;
/*------ template functions ------ */
#ifndef getchar_unlocked
#define getchar_unlocked getchar
#endif
template<class T> inline void sc(T &x){register int c = gc();x = 0;int neg = 0;for(;((c<48 | c>57) && c != '-');c = gc());
if(c=='-') {neg=1;c=gc();}for(;c>47 && c<58;c = gc()) {x = (x<<1) + (x<<3) + c - 48;}if(neg) x=-x;}
template <class T> inline T bigmod(T p,T e,T M){LL ret = 1;for(; e > 0; e >>= 1){if(e & 1) ret = (ret * p) % M;p = (p * p) % M;} return (T)ret;}
template <class T> inline T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template <class T> inline T modinverse(T a,T M){return bigmod(a,M-2,M);}
/*************************** END OF TEMPLATE ****************************/
const int N = 100005;
vector<int> Lucky;
bool L[10005];
void gen(int u)
{
if(u>10000) return;
if(u>0) Lucky.pb(u);
gen(10*u+4);
gen(10*u+7);
}
int A[N];
int ia[N];
int block = 320;
int delta[500];
int cnt[500][10005];
void updateElement(int pos,int d)
{
int id = pos/block;
if(ia[id]!=-1 && L[A[pos] + delta[id]]) ia[id] --;
cnt[id][A[pos]] --;
A[pos] += d;
cnt[id][A[pos]] ++;
if(ia[id]!=-1 && L[A[pos] + delta[id]]) ia[id] ++;
}
void updateBlock(int id,int d)
{
delta[id] += d;
ia[id] = -1;
}
void update(int lo,int hi,int d)
{
int i;
for(i=lo; i%block&&i<=hi; i ++ ) {
updateElement(i,d);
}
for(; i + block-1 <= hi; i += block) {
updateBlock(i/block,d);
}
for(;i <= hi ; i ++ ) updateElement(i,d);
}
int queryElement(int pos)
{
int id = pos/block;
if(L[A[pos] + delta[id]] ) return 1;
return 0;
}
int queryBlock(int id)
{
if(ia[id]>=0) return ia[id];
int p = delta[id];
int res = 0;
for(int i = 0;i < Lucky.size() ; i++ ) {
int c = Lucky[i] - p;
if(c>0) res += cnt[id][c];
}
return ia[id] = res;
}
int query(int lo,int hi)
{
int i,j;
int res = 0;
for(i=lo;i%block&&i<=hi;i++){
res += queryElement(i);
}
for( ; i + block -1 <= hi ; i+= block){
res += queryBlock(i/block);
}
for(;i<=hi;i++) res += queryElement(i);
return res;
}
int main()
{
ms(ia,-1);
gen(0);
sort(all(Lucky));
forn(i,Lucky.size()) L[Lucky[i]] = 1;
DII(n,q);
forn(i,n) sc(A[i]);
forn(i,n){
cnt[i/block][A[i]] ++;
}
int lo,hi;
char t[10];
while(q--){
scanf("%s%d%d",t,&lo,&hi);
lo--,hi--;
if(t[0]=='c'){
int res = query(lo,hi);
printf("%d\n",res);
}
else {
DI(d);
update(lo,hi,d);
}
}
}
Segment Tree Solution with lazy – propagration :
For each node in the segment Tree
1. If it is a leaf node, Store The value,distance to the nearest lucky number , lazy value, sum
2. If not , Then store sum , near,lazy
struct Node
{
int sum,near,lazy,v;
Node(){sum=0,near=inf,lazy=0,v=-1;}
};
Merging The tree :
The whole node ,stores The nearest distance to the lucky number among all the elements of the segments
So merging will calculate, minimum of left child and right child
The sum = sum_of_Left + sum_of_Right;
void Merge(int n)
{
T[n].near = min(T[lc].near - T[lc].lazy , T[rc].near - T[rc].lazy);
T[n].sum = T[lc].sum + T[rc].sum;
}
Building The Tree :
void build(int n,int b,int e)
{
if(b==e){
T[n].near= dis[A[b]];
T[n].v = A[b];
T[n].sum = L[A[b]];
T[n].lazy = 0;
return;
}
int mid = (b+e)/2;
build(lc,b,mid);
build(rc,mid+1,e);
Merge(n);
}
For lazy Propagation We need to push
The function for this
void push(int n)
{
T[lc].lazy += T[n].lazy;
T[rc].lazy += T[n].lazy;
if(T[n].lazy) { T[n].near -= T[n].lazy;T[n].lazy = 0;}
if(T[n].sum == 0 ) T[lc].sum = T[rc].sum = 0;
}
Query is same as the standard query Function
int query(int n,int b,int e,int i,int j)
{
if(b>=i&&e<=j) return T[n].sum;
if(b!=e) push(n);
int mid = (b+e)/2;
int ret =0;
if(i<=mid)ret += query(lc,b,mid,i,j);
if(j>mid)ret += query(rc,mid+1,e,i,j);
return ret;
}
Update : Update is Tricky,
1. If There is any chance that, We have attained or crossed a lucky Number , We go to that index( all the indices,and update them)
2. If for a segment , The distance to the nearest lucky Number > val(To add ) + lazy , Then There can be no lucky Number on this segment, T[n].sum = 0, return;
void update(int n,int b,int e,int i,int j,int val)
{
if(b!=e) push(n);
if(b>= i && e<= j ) {
if(b==e){
T[n].v += T[n].lazy + val;
T[n].lazy = 0;
T[n].sum =L[T[n].v];
T[n].near = dis[T[n].v];
return ;
}
if(T[n].near > T[n].lazy + val ){
T[n].lazy += val;
T[n].sum = 0;
return ;
}
}
int mid = (b+e)/2;
if(i<=mid) update(lc,b,mid,i,j,val);
if(j>mid)update(rc,mid+1,e,i,j,val);
Merge(n);
}
FinalCode:
#include <bits/stdc++.h>
using namespace std;
/*------- Constants---- */
#define LL long long
#define ull unsigned long long
#define mod 1000000007
#define MEMSET_INF 63
#define MEM_VAL 1061109567
#define forn(i,n) for( int i=0 ; i < n ; i++ )
#define mp(i,j) make_pair(i,j)
#define lop(i,a,b) for( int i = (a) ; i < (b) ; i++)
#define pb(a) push_back((a))
#define all(x) (x).begin(),(x).end()
#define gc getchar_unlocked
#define PI acos(-1.0)
#define inf 1<<30
#define lc ((n)<<1)
#define rc ((n)<<1 |1)
#define db(x) cout << #x << " -> " << x << endl;
#define DI(n) int n;sc(n)
#define DII(a,b) int a,b;sc(a);sc(b)
#define DIII(a,b,c) int a,b,c;sc(a);sc(b);sc(c)
#define min(a,b) ((a)>(b) ? (b) : (a) )
#define max(a,b) ((a)>(b) ? (a):(b))
/*---- short Cuts ------- */
#define ms(ara_name,value) memset(ara_name,value,sizeof(ara_name))
typedef pair<int, int> ii;
typedef vector<int > vi ;
/*------ template functions ------ */
#ifndef getchar_unlocked
#define getchar_unlocked getchar
#endif
template<class T> inline void sc(T &x){register int c = gc();x = 0;int neg = 0;for(;((c<48 | c>57) && c != '-');c = gc());
if(c=='-') {neg=1;c=gc();}for(;c>47 && c<58;c = gc()) {x = (x<<1) + (x<<3) + c - 48;}if(neg) x=-x;}
template <class T> inline T bigmod(T p,T e,T M){LL ret = 1;for(; e > 0; e >>= 1){if(e & 1) ret = (ret * p) % M;p = (p * p) % M;} return (T)ret;}
template <class T> inline T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template <class T> inline T modinverse(T a,T M){return bigmod(a,M-2,M);}
/*************************** END OF TEMPLATE ****************************/
const int N = 1e5+5;
vector<int> Lucky;
bool L[N];
int A[N];
int dis[N];
void gen(int u)
{
if(u>10000) return;
if(u>0) Lucky.pb(u);
gen(10*u+4);
gen(10*u+7);
}
struct Node
{
int sum,near,lazy,v;
Node(){sum=0,near=inf,lazy=0,v=-1;}
};
Node T[4*N];
void Merge(int n)
{
T[n].near = min(T[lc].near - T[lc].lazy , T[rc].near - T[rc].lazy);
T[n].sum = T[lc].sum + T[rc].sum;
}
void push(int n)
{
T[lc].lazy += T[n].lazy;
T[rc].lazy += T[n].lazy;
if(T[n].lazy) { T[n].near -= T[n].lazy;T[n].lazy = 0;}
if(T[n].sum == 0 ) T[lc].sum = T[rc].sum = 0;
}
void build(int n,int b,int e)
{
if(b==e){
T[n].near= dis[A[b]];
T[n].v = A[b];
T[n].sum = L[A[b]];
T[n].lazy = 0;
return;
}
int mid = (b+e)/2;
build(lc,b,mid);
build(rc,mid+1,e);
Merge(n);
}
int query(int n,int b,int e,int i,int j)
{
if(b>=i&&e<=j) return T[n].sum;
if(b!=e) push(n);
int mid = (b+e)/2;
int ret =0;
if(i<=mid)ret += query(lc,b,mid,i,j);
if(j>mid)ret += query(rc,mid+1,e,i,j);
return ret;
}
void update(int n,int b,int e,int i,int j,int val)
{
if(b!=e) push(n);
if(b>= i && e<= j ) {
if(b==e){
T[n].v += T[n].lazy + val;
T[n].lazy = 0;
T[n].sum =L[T[n].v];
T[n].near = dis[T[n].v];
db("akshd");
return ;
}
if(T[n].near > T[n].lazy + val ){
T[n].lazy += val;
T[n].sum = 0;
return ;
}
}
int mid = (b+e)/2;
if(i<=mid) update(lc,b,mid,i,j,val);
if(j>mid)update(rc,mid+1,e,i,j,val);
Merge(n);
}
int main()
{
gen(0);
dis[N-1] = inf;
for(auto a : Lucky) L[a] = 1;
for(int i = N-2; i >= 0; i-- ) {
if(L[i+1]) dis[i]= 1;
else dis[i] = 1 + dis[i+1];
}
DII(n,q);
forn(i,n){
sc(A[i]);
}
build(1,0,n-1);
char op[10];
int lo,hi;
forn(i,q){
scanf("%s%d%d",op,&lo,&hi);
lo--,hi--;
if(op[0]=='c'){
printf("%d\n", query(1,0,n-1,lo,hi));
}
else {
DI(d);
update(1,0,n-1,lo,hi,d);
}
}
}