Skip to content
thecscience
THECSICENCE

Learn everything about computer science

  • Home
  • Human values
  • NCERT Solutions
  • HackerRank solutions
    • HackerRank Algorithms problems solutions
    • HackerRank C solutions
    • HackerRank C++ solutions
    • HackerRank Java problems solutions
    • HackerRank Python problems solutions
thecscience
THECSICENCE

Learn everything about computer science

HackerRank How Many Substrings? Solution

Yashwant Parihar, May 5, 2023May 5, 2023

In this post, we will solve HackerRank How Many Substrings? Problem Solution.

Consider a string of n characters, s, of where each character is indexed from 0 ton – 1. You are given q queries in the form of two integer indices: left and right. For each query, count and print the number of different substrings of $ in the inclusive range between left and right.
Note: Two substrings are different if their sequence of characters differs by at least one. For example, given the string s = aab, substrings 8[0,0]=a and 8[1,1] = a are the same but substrings $[0,1] = aa and $[1,2] = ab are different. | |
Input Format
The first line contains two space-separated integers describing the respective values of n
and q.
The second line contains a single string denoting s.
Each of the q subsequent lines contains two space-separated integers describing the respective values of left and right for a query.

Output Format
For each query, print the number of different substrings in the inclusive range between
index left and index right on a new line.

Sample Input 0

5 5
aabaa
1 1
1 4
1 1
1 4
0 2

Sample Output 0

1
8
1
8
5

Explanation 0
Given s = aabaa, we perform the following q = 5 queries:
1.1 1: The only substring of a is itself, so we print 1 on a new line.

  1. 1 4: The substrings of abaa are a, b, ab, ba, aa, aba, baa, and abaa, so we print 8 on a new line.
  2. 1 1: The only substring of a is itself, so we print 1 on a new line.
  3. 1 4: The substrings of abaa are a, b, ab, ba, aa, aba, baa, and abaa, so we print 8 on a new line.
    5.0 2: The substrings of aab are a, b, aa, ab, and aab, so we print 5 on a new line.
HackerRank How Many Substrings? Problem Solution
HackerRank How Many Substrings? Problem Solution

How Many Substrings? C++ Solution

#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define SZ(x) ((int)((x).size()))
#define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++)
#define per(i,j,k) for(int i=(int)j;i>=(int)k;i--)
using namespace std;
typedef long long LL;
typedef double DB;
const DB pi=acos(-1.0);
const int N=100005;
int go[N<<1][26],fail[N<<1],len[N<<1],tot,last;
int n;
int cnt=0;
namespace seg{
    int tag[N<<2];
    LL sum[N<<2];
    inline void Tag(int me,int l,int r,int v){
        tag[me]+=v;
        sum[me]+=(r-l+1)*1ll*v;
    }
    inline void down(int me,int l,int r){
        if(tag[me]==0)return;
        int mid=(l+r)>>1;
        Tag(me<<1,l,mid,tag[me]);
        Tag(me<<1|1,mid+1,r,tag[me]);
        tag[me]=0;
    }
    void add(int me,int l,int r,int x,int y,int v){
        //if(l==1&&r==n)printf("add %d %d %d\n",x,y,v);
        if(l^r)down(me,l,r);
        if(x<=l&&r<=y){
            Tag(me,l,r,v);
            return;
        }
        int mid=(l+r)>>1;
        if(x<=mid)add(me<<1,l,mid,x,y,v);
        if(y>mid)add(me<<1|1,mid+1,r,x,y,v);
        sum[me]=sum[me<<1]+sum[me<<1|1];
    }
    LL ask(int me,int l,int r,int x,int y){
        if(l^r)down(me,l,r);
        if(x<=l&&r<=y)return sum[me];
        int mid=(l+r)>>1;
        LL ret=0;
        if(x<=mid)ret+=ask(me<<1,l,mid,x,y);
        if(y>mid)ret+=ask(me<<1|1,mid+1,r,x,y);
        return ret;
    }
    void Do(int pre,int now,int L,int R){
        if(L>R)return;
        ++cnt;
        //printf("_%d %d %d %d\n",pre,now,L,R);
        if(pre)add(1,1,n,pre-R+1,pre-L+1,-1);
        add(1,1,n,now-R+1,now-L+1,1);
    }
};
namespace lct{
    int l[N<<2],r[N<<2],fa[N<<2];
    int last[N<<2];
    inline bool top(int x){return (!fa[x])||(l[fa[x]]!=x&&r[fa[x]]!=x);}
    inline void left(int x){
        int y=fa[x];int z=fa[y];
        r[y]=l[x];if(l[x])fa[l[x]]=y;
        fa[x]=z;if(l[z]==y)l[z]=x;else if(r[z]==y)r[z]=x;
        l[x]=y;fa[y]=x;
    }
    inline void right(int x){
        int y=fa[x];int z=fa[y];
        l[y]=r[x];if(r[x])fa[r[x]]=y;
        fa[x]=z;if(l[z]==y)l[z]=x;else if(r[z]==y)r[z]=x;
        r[x]=y;fa[y]=x;
    }
    inline void down(int x){
        if(l[x])last[l[x]]=last[x];
        if(r[x])last[r[x]]=last[x];
    }
    int q[N<<2];
    inline void splay(int x){
        q[q[0]=1]=x;
        for(int k=x;!top(k);k=fa[k])q[++q[0]]=fa[k];
        per(i,q[0],1)down(q[i]);
        while(!top(x)){
            int y=fa[x];int z=fa[y];
            if(top(y)){
                if(l[y]==x)right(x);else left(x);
            }
            else{
                if(r[z]==y){
                    if(r[y]==x)left(y),left(x);
                    else right(x),left(x);
                }
                else{
                    if(l[y]==x)right(y),right(x);
                    else left(x),right(x);
                }
            }
        }
    }
    void Access(int x,int cov){
        int y=0;
        for(;x;y=x,x=fa[x]){
            splay(x);
            down(x);
            r[x]=0;

            int L,R;
            int z=x;
            while(l[z])z=l[z];
            L=len[fail[z]]+1;
            splay(z);splay(x);
            z=x;
            while(r[z])z=r[z];
            R=len[z];
            splay(z);splay(x);
            seg::Do(last[x],cov,L,R);
            r[x]=y;
            last[x]=cov;
        }
    }
    void SetFa(int x,int y,int po){
        fa[x]=y;
        Access(x,po);
    }
    void split(int x,int y,int d){
        splay(y);
        down(y);
        r[y]=0;
        fa[d]=y;
        splay(x);
        fa[x]=d;
        last[d]=last[x];
    }
};
namespace sam{
    void init(){
        tot=last=1;
    }
    void expended(int x,int po){
        int gt=++tot;len[gt]=len[last]+1;int p=last;last=tot;
        for(;p&&(!go[p][x]);p=fail[p])go[p][x]=gt;
        if(!p){
            fail[gt]=1;
            lct::SetFa(gt,1,po);
            return;
        }
        int xx=go[p][x];
        if(len[xx]==len[p]+1){
            fail[gt]=xx;
            lct::SetFa(gt,xx,po);
            return;
        }
        int tt=++tot;
        len[tt]=len[p]+1;
        fail[tt]=fail[xx];
        int dt=fail[xx];
        fail[xx]=fail[gt]=tt;
        lct::split(xx,dt,tt);
        lct::SetFa(gt,tt,po);
        rep(i,0,25)go[tt][i]=go[xx][i];
        for(;p&&(go[p][x]==xx);p=fail[p])go[p][x]=tt;
    }
};
int Q;
char str[N];
int qL[N];
vector<int>que[N];
LL ans[N];
void Main(){
    rep(i,1,n){
        sam::expended(str[i]-'a',i);
        rep(j,0,que[i].size()-1){
            int id=que[i][j];
            ans[id]=seg::ask(1,1,n,qL[id],n);
        }
    }
}
void init(){
    scanf("%d%d",&n,&Q);
    scanf("%s",str+1);
    rep(i,1,Q){
        int r;scanf("%d%d",&qL[i],&r);
        qL[i]++;r++;
        que[r].pb(i);
    }
    sam::init();
}
void Output(){
    rep(i,1,Q)printf("%lld\n",ans[i]);
}
int main(){
    init();
    Main();
    Output();
    return 0;
}  

How Many Substrings? C Sharp Solution

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Solution {

    static void Main(String[] args) {
        string[] tokens_n = Console.ReadLine().Split(' ');
        int n = Convert.ToInt32(tokens_n[0]);
        int q = Convert.ToInt32(tokens_n[1]);
        string s = Console.ReadLine();
        var queries = new Query[q];
        for(int a0 = 0; a0 < q; a0++){
            string[] tokens_left = Console.ReadLine().Split(' ');
            queries[a0] = new Query(Convert.ToInt32(tokens_left[0]), Convert.ToInt32(tokens_left[1]));
        }
        SubstringCounter.solve(s.ToCharArray(), queries);    
        foreach (Query e in queries)
            Console.WriteLine(e.Answer);
    }
}
public class SubstringCounter
{
    public static void solve(char[] str, Query[] queries)
    {

        int[] suffixArray = SuffixArray.BuildSuffixArray(str);
        int[] suffixArrayInverse = new int[str.Length];
        for (int i = 0; i < str.Length; i++)
        {
            suffixArrayInverse[suffixArray[i]] = i;
        }
        int[] lcp = SuffixArray.BuildLcpKasai(suffixArray, suffixArrayInverse, str);

        //defaultdict instead of List?
        var queriesIndexedByLeft = new List<Query>[str.Length];
        for (int i = 0; i < str.Length; i++)
            queriesIndexedByLeft[i] = new List<Query>();

        foreach (Query query in queries)
            queriesIndexedByLeft[query.Left].Add(query);

        var maximumPrefixContainingInterval = LcpIntervalHelper.BuildIntervals(lcp);

        SubstringSum substringSum = new SubstringSum(str.Length);
        for (int i = str.Length - 1; i >= 0; i--)
        {
            //No ValueTuples in hacker rank :o(
            Stack<Tuple<int, int>> tups = LcpIntervalHelper.GetLastSeen(i, 
                                                                        maximumPrefixContainingInterval,                                                                                            suffixArrayInverse);

            int matchedLcp = 0;
            while (tups.Count > 0)
            {
                var tup = tups.Pop();
                int j = tup.Item1;
                int newLcp = tup.Item2;
                substringSum.addRange(j + matchedLcp, j + newLcp - 1);
                matchedLcp = newLcp;
            }

            foreach (Query query in queriesIndexedByLeft[i])
            {
                query.Answer = substringSum.getSum(query.Left, query.Right);
            }
        }
    }
}
public class Query
{
    public int Left { get; }
    public int Right { get; }
    public long Answer { get; set; }

    public Query(int left, int right)
    {
        this.Left = left;
        this.Right = right;
    }
}


//When we want count substrings whilst we change the right value of a string for a prebuilt suffix array the standard
//Lcp array is less helpful as it is not ordered in terms of the original string and will become full of holes. With holes
//we would need to consider the minimum of all intervening missing LCP elements to calculate the LCP between two elements. 
//
//So instead we flip the idea on its side to have a set of LcpIntervals. Each lcp interval contains all Suffixes in
//the Suffix Array with a minimum lcp.
//
//At least the minimum LCP of all but the first element in the interval can be used to reduce the substring count.
//For each Suffix Array item we only store the LcpInterval with the maximum MinimumLcp. This ensures at most n
//intervals.
//So as the right value of a query changes the problem becomes how to spot if this is the first suffix in the
//interval or not.
//We do this by processing the string in reverse order and noting the leftmost time a string in the interval is seen.

// Each LcpInterval contains a link to its enclosing superinterval, each interval will be enclosed by one and only
// one Super-Interval, apart from the root.
// I suppose you could consider it to be a tree and perhaps I should have researched if an appropriate standard
// pattern / data structure existed.

// The curious thing is that when I look at the finished working result I notice that Left and Right of LcpInterval 
// don't actually appear to be needed. But if I remove them the motivating idea of the code would be impossible to
// understand. I will leave them in as comments, with the caveat of all comments that as they don't
// affect the correct working of the code they may be wrong.


public class LcpIntervalHelper
{
    public class LcpInterval
    {
        //public int Left { get; }
        //public int Right { get; set; }
        public LcpInterval SuperLcpInterval { get; set; }
        public int MinimumLcp { get; }
        public int LastSeen { get; set; }


        //public LcpInterval(int length, int left, int right, LcpInterval superLcpInterval)
        public LcpInterval(int length, LcpInterval superLcpInterval)
        {
            MinimumLcp = length;
            //Left = left;
            //Right = right;
            SuperLcpInterval = superLcpInterval;
            LastSeen = int.MaxValue;
        }

        public override string ToString()
        {
            return
                   //                      $"{nameof(Left)}: {Left}, " +
                   //                      $"{nameof(Right)}: {Right}" +
                   $"{nameof(MinimumLcp)}: {MinimumLcp} " +
                   $"{nameof(LastSeen)}: {LastSeen} ";
        }
    }

    public static Stack<Tuple<int, int>> GetLastSeen(int i, LcpInterval[] lcpIntervals, int[] saInverse)
    {
        var interval = lcpIntervals[saInverse[i]];
        var ret = new Stack<Tuple<int, int>>();
        int lastSeen = int.MaxValue;

        while (interval.SuperLcpInterval != null)
        {
            if (interval.LastSeen < lastSeen)
            {
                ret.Push(new Tuple<int, int>(interval.LastSeen, interval.MinimumLcp));
                lastSeen = interval.LastSeen;
            }
            interval.LastSeen = i;
            interval = interval.SuperLcpInterval;
        }

        return ret;
    }

    public static LcpInterval[] BuildIntervals(int[] lcp)
    {
        // the root interval should be the only one with parent == null
        //var interval = new LcpInterval(0, 0, lcp.Length , null);
        var interval = new LcpInterval(0, null);

        var suffixArrayIntervals = new LcpInterval[lcp.Length];

        //Step through lcp build interval assigning max count interval to each item of the initial string.
        //Each interval has a link to the containit interval.

        for (int i = 0; i < lcp.Length - 1; i++)
        {
            //start off we are in the current interval
            //We know we are in the same interval as indexes to the left. We might be in 
            //a sub interval if we have a higher matching prefex to the right.
            suffixArrayIntervals[i] = interval;
            LcpInterval oldLcpInterval = interval;
            while (interval.MinimumLcp > lcp[i + 1] && interval.SuperLcpInterval != null)
            {
                //close the current ineterval
                //                  interval.Right = i;
                oldLcpInterval = interval;
                interval = interval.SuperLcpInterval;
            }

            if (interval.MinimumLcp < lcp[i + 1])
            {
                if (interval != oldLcpInterval)
                {
                    // We have closed a higher LCP interval but are inserting a new one between it and its previous
                    // SuperInterval.
                    // e.g. oldInterval was MinimumLCP = 2 with SuperInterval MinimumLCP=0
                    // but we now whish to open an interval MinimumLCP=1

                    //interval = new LcpInterval(lcp[i + 1], oldLcpInterval.Left, lcp.Length - 1, interval);
                    interval = new LcpInterval(lcp[i + 1], interval);

                    oldLcpInterval.SuperLcpInterval = interval;
                }
                else
                {
                    // Starting a new interval from the previous interval with higher LCP
                    //interval = new LcpInterval(lcp[i + 1], i, lcp.Length - 1, interval);
                    interval = new LcpInterval(lcp[i + 1], interval);
                    suffixArrayIntervals[i] = interval;
                }
            }

        }
        suffixArrayIntervals[lcp.Length - 1] = interval;
        return suffixArrayIntervals;
    }
}
// For the Hackerrank problem we are interested in how the matching SuffixArray LCP values to reduce the number
// of substrings
//
// Without matching LCP prefixes the number of substrings is n=(right+1-left)(right+2-left)/2
// This is just math for SUM(i=left to right){i}. This is clearly Trivial to calculate.
//
// So we are only really interested in LCP values and when they should be used to reduce substring count.
// When we have a matching prefix in SuffixArray index j > i. The potential to use those matching prefixes 
// drops off as the j extends further to the right i.e j+lcp > right.
// So naively we want
//  for (int k = j; j < j+lcp; j++)
//  {
//      OffsetSum.UpdateValue(k, 1);
//  }
// And we can use OffsetSum to reduce the number of Substrings as we would normally for an LCP/SuffixArray
// However if lcp is > 4 potentially much > 4 this becomes slow.
// So we simulate this by using a math formula
// And calculate the sum using k * LinearSum(k) + OffsetSum(k)
//
// For instance for n = 13
// left =3 right =10 i.e Offset = [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 , 0, 0]
//
// Can be simulated with
//  Offset = [0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0 ]
//  Linear = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0 ]
//
// Sum( 1 ) = SumOffset(1) + SumLinear(1) = 0 + 1*0 = 0
// Sum( 3 ) = SumOffset(3) + SumLinear(3) = -2 + 3*1 = 1
// Sum( 4 ) = SumOffset(4) + SumLinear(4) = -2 + 4*1 = 2
// Sum( 5 ) = SumOffset(5) + SumLinear(5) = -2+ 5*1 = 3
//
// Sum( 8 ) = SumOffset(8) + SumLinear(8) = -2 + 8*1 = 6
// Sum( 9 ) = SumOffset(9) + SumLinear(9) = -2 + 9*1 = 7
// Sum( 10 ) = SumOffset(10) + SumLinear(10) = 8 + 10*0 = 8
// Sum( 11 ) = SumOffset(11) + SumLinear(11) = 8  + 11*0 = 8
// Sum( 12 ) = SumOffset(8) + SumLinear(8) = 8 + 12*0 = 8

public class SubstringSum
{
    class FenwickTree
    {
        private long[] fenwickArray;

        public FenwickTree(int n)
        {
            fenwickArray = new long[n];
        }

        public void UpdateValue(int index, long value)
        {
            while (index < fenwickArray.Length)
            {
                fenwickArray[index] += value;
                index += LSB(index + 1);
            }
        }

        private int LSB(int i)
        {
            return i & -i;
        }

        public long GetValue(int i)
        {
            long sum = 0;
            while (i != 0)
            {
                sum += fenwickArray[i - 1];
                i -= LSB(i);
            }
            return sum;
        }
    }

    private FenwickTree LinearSum;
    private FenwickTree OffsetSum;
    private int n;

    public SubstringSum(int n)
    {
        this.n = n;
        LinearSum = new FenwickTree(n);
        OffsetSum = new FenwickTree(n);
    }

    public void add(int i, long v)
    {
        if (i < n)
        {
            OffsetSum.UpdateValue(i, v);
        }
    }


    public void addRange(int left, int right)
    {
        LinearSum.UpdateValue(left, 1);
        OffsetSum.UpdateValue(left, 1 - left);

        LinearSum.UpdateValue(right, -1);
        OffsetSum.UpdateValue(right, right);
    }

    public long getSum(int i)
    {
        long li = i;
        return li * LinearSum.GetValue(i + 1) + OffsetSum.GetValue(i + 1);
    }

    //inclusive right
    public long getSum(int left, int right)
    {
        // I don't understand the rules of implicit type conversions in intermediate calculations.
        // so better safe than sorry. 100k^2 is too big for an int.
        long rightlong = right;
        long leftlong = left;

        return (rightlong + 1 - leftlong) * (rightlong + 2 - leftlong) / 2 - getSum(right);
    }
}

public static class SuffixArray
{

    //Naive c# sort LCP generation for test10 n=100,000 was 973 ms
    //This Kasai trick bought it down to 6 ms
    //The simple idea is that if a suffix matches k characters. The suffix generated by one character further along
    //in the string must match at least k-1 characters, i.e. just use the previous matching prefix one char
    //further along. 
    //So we don't need to check the first k-1 chars. This gives us an O(n) sort.
    public static int[] BuildLcpKasai(int[] suffixArray, int[] suffixArrayInverse, char[] str)
    {
        int[] lcp = new int[suffixArray.Length];

        int n = suffixArray.Length;
        int k = 0;
        for (int i = 0; i < n; i++)
        {
            int inversei = suffixArrayInverse[i];
            if (inversei == 0)
            {
                k = 0;
                continue;
            }
            int j = suffixArray[inversei - 1];
            while (i + k < n && j + k < n && str[i + k] == str[j + k])
                k++;

            lcp[inversei] = k;
            if (k > 0)
                k--;

        }
        return lcp;
    }
    // Naive SuffixArray creation using CSharp Collection.sort was too slow approx 6 seconds for 100k 
    // SO I used a more efficient algorithm
    // Code adapted from:
    // http://www.cs.cmu.edu/afs/cs/academic/class/15492-f07/www/handouts/ks-icalp03.pdf
    // Juha Karkkainen and Peter Sanders
    public static int[] BuildSuffixArray(char[] str)
    {

        int[] s = new int[str.Length + 3];
        int[] SA = new int[str.Length];

        for (int i = 0; i < str.Length; i++)
            s[i] = str[i];
        s[str.Length] = 0;
        s[str.Length + 1] = 0;
        s[str.Length + 2] = 0;

        suffixArray(s, SA, str.Length, 128);
        return SA;
    }

    static int GetI(int[] SA12, int n0, int t)
    {
        return (SA12[t] < n0 ? SA12[t] * 3 + 1 : (SA12[t] - n0) * 3 + 2);
    }

    static bool leq(int a1, int a2, int b1, int b2)
    {
        // lexic. order for pairs
        return (a1 < b1 || a1 == b1 && a2 <= b2);
    } // and triples

    static bool leq(int a1, int a2, int a3, int b1, int b2, int b3)
    {
        return (a1 < b1 || a1 == b1 && leq(a2, a3, b2, b3));
    }

    // stably sort a[0..n-1] to b[0..n-1] with keys in 0..K from r
    static void radixPass(int[] a, int[] b, int[] r, int rOffset, int n, int K)
    {
        // count occurrences
        int[] c = new int[K + 1]; // counter array
        for (int i = 0; i <= K; i++) c[i] = 0; // reset counters
        for (int i = 0; i < n; i++) c[r[rOffset + a[i]]]++; // count occurences
        for (int i = 0, sum = 0; i <= K; i++)
        {
            // exclusive prefix sums
            int t = c[i];
            c[i] = sum;
            sum += t;
        }

        for (int i = 0; i < n; i++) b[c[r[rOffset + a[i]]]++] = a[i]; // sort
    }

    // find the suffix array SA of s[0..n-1] in {1..K}^n
    // require s[n]=s[n+1]=s[n+2]=0, n>=2
    static void suffixArray(int[] s, int[] SA, int n, int K)
    {
        int n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3, n02 = n0 + n2;
        int[] s12 = new int[n02 + 3];
        s12[n02] = s12[n02 + 1] = s12[n02 + 2] = 0;
        int[] SA12 = new int[n02 + 3];
        SA12[n02] = SA12[n02 + 1] = SA12[n02 + 2] = 0;
        int[] s0 = new int[n0];
        int[] SA0 = new int[n0];

        // generate positions of mod 1 and mod  2 suffixes
        // the "+(n0-n1)" adds a dummy mod 1 suffix if n%3 == 1
        for (int i = 0, j = 0; i < n + (n0 - n1); i++)
            if (i % 3 != 0)
                s12[j++] = i;

        // lsb radix sort the mod 1 and mod 2 triples
        radixPass(s12, SA12, s, 2, n02, K);
        radixPass(SA12, s12, s, 1, n02, K);
        radixPass(s12, SA12, s, 0, n02, K);

        int name = 0, c0 = -1, c1 = -1, c2 = -1;
        for (int i = 0; i < n02; i++)
        {
            if (s[SA12[i]] != c0 || s[SA12[i] + 1] != c1 || s[SA12[i] + 2] != c2)
            {
                name++;
                c0 = s[SA12[i]];
                c1 = s[SA12[i] + 1];
                c2 = s[SA12[i] + 2];
            }

            if (SA12[i] % 3 == 1)
            {
                s12[SA12[i] / 3] = name;
            } // left half
            else
            {
                s12[SA12[i] / 3 + n0] = name;
            } // right half
        }

        if (name < n02)
        {
            suffixArray(s12, SA12, n02, name);
            // store unique names in s12 using the suffix array 
            for (int i = 0; i < n02; i++) s12[SA12[i]] = i + 1;
        }
        else // generate the suffix array of s12 directly
            for (int i = 0; i < n02; i++)
                SA12[s12[i] - 1] = i;

        // stably sort the mod 0 suffixes from SA12 by their first character
        for (int i = 0, j = 0; i < n02; i++)
            if (SA12[i] < n0)
                s0[j++] = 3 * SA12[i];
        radixPass(s0, SA0, s, 0, n0, K);

        // merge sorted SA0 suffixes and sorted SA12 suffixes
        for (int p = 0, t = n0 - n1, k = 0; k < n; k++)
        {
            int i = GetI(SA12, n0, t); // pos of current offset 12 suffix
            int j = SA0[p]; // pos of current offset 0  suffix
            if (SA12[t] < n0
                ? leq(s[i], s12[SA12[t] + n0], s[j], s12[j / 3])
                : leq(s[i], s[i + 1], s12[SA12[t] - n0 + 1], s[j], s[j + 1], s12[j / 3 + n0]))
            {
                // suffix from SA12 is smaller
                SA[k] = i;
                t++;
                if (t == n02)
                {
                    // done --- only SA0 suffixes left
                    for (k++; p < n0; p++, k++) SA[k] = SA0[p];
                }
            }
            else
            {
                SA[k] = j;
                p++;
                if (p == n0)
                {
                    // done --- only SA12 suffixes left
                    for (k++; t < n02; t++, k++) SA[k] = GetI(SA12, n0, t);
                }
            }
        }
    }
}

How Many Substrings? Java Solution

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.InputMismatchException;
import java.util.List;

public class How_Many_Substrings {
    InputStream is;
    PrintWriter out;
    String INPUT = "";
    
    void solve()
    {
        int n = ni(), Q = ni();
        char[] s = ns(n);
        int[][] qs = new int[Q][];
        for(int z = 0;z < Q;z++){
            qs[z] = new int[]{ni(), ni(), z};
        }
        Arrays.sort(qs, new Comparator<int[]>() {
            public int compare(int[] a, int[] b) {
                return a[1] - b[1];
            }
        });

        SuffixAutomatonOfBit sa = SuffixAutomatonOfBit.build(s);
        sa.sortTopologically();
        SuffixAutomatonOfBit.Node[] nodes = sa.nodes;
        int[] from = new int[nodes.length-1];
        int[] to = new int[nodes.length-1];
        int p = 0;
        for(SuffixAutomatonOfBit.Node node : nodes){
            if(node.id >= 1){
                from[p] = node.link.id; to[p] = node.id; p++;
            }
        }
        assert p == nodes.length-1;
        int[][] g = packU(nodes.length, from, to);
        int[][] pars = parents3(g, 0);
        int[] par = pars[0], ord = pars[1], dep = pars[2];
        HeavyLightDecomposition hld = new HeavyLightDecomposition(g, par, ord, dep);
        int m = hld.cluspath.length;
        SegmentTreeOverwrite[] sts = new SegmentTreeOverwrite[m];
        for(int i = 0;i < m;i++){
            sts[i] = new SegmentTreeOverwrite(hld.cluspath[i].length);
        }
        
        int[] base = new int[n];
        int qp = 0;
        int np = 0;
        long[] ft0 = new long[n+3];
        long[] ft1 = new long[n+3];
        long[] ans = new long[Q];
        for(int i = 0;i < n;i++){
            while(!(nodes[np].len == i+1 && nodes[np].original == null))np++;
            base[i] = np;
//            tr("base", base[i]);
            
            // 5 3 1 0
            // 5 3 1 0
            // 8 6 3 1 0 ?
            // aaba
            
            // delete
            int cur = 0;
            int ppos = 0;
            while(true){
                int last = sts[hld.clus[cur]].get(hld.clusiind[cur]);
                if(last == -1)break;
                int lca = hld.lca(base[last], base[i]);
                // delete from lca to cur
    //            nodes[cur].len, nodes[lca].len;
                int inf = last-nodes[lca].len+1;
                int sup = last-ppos+1;
//                tr("del", last, ppos, nodes[lca].len, inf, sup);
                // _/
                addFenwick(ft0, 0, -(sup-inf));
                addFenwick(ft0, sup+1, +(sup-inf));
                addFenwick(ft0, inf+1, -(inf+1));
                addFenwick(ft0, sup+1, +inf+1);
                addFenwick(ft1, inf+1, 1);
                addFenwick(ft1, sup+1, -1);
//                tr(i, restoreRangeFenwick(ft0, ft1));
                ppos = nodes[lca].len;
                assert dep[base[i]]-dep[lca]-1 >= 0;
                cur = hld.ancestor(base[i], dep[base[i]]-dep[lca]-1);
            }
            // x
            //b a
            //   a
            
            // paint
            int cx = hld.clus[base[i]]; // cluster
            int ind = hld.clusiind[base[i]]; // pos in cluster
            while(true){
                sts[cx].update(0, ind+1, i);
                int con = par[hld.cluspath[cx][0]];
                if(con == -1)break;
                ind = hld.clusiind[con];
                cx = hld.clus[con];
            }
            
//            tr(i, restoreRangeFenwick(ft0, ft1));
            addFenwick(ft0, 0, i+1+1);
            addFenwick(ft0, i+1+1, -(i+1+1));
            addFenwick(ft1, 0, -1);
            addFenwick(ft1, i+1+1, 1);
//            tr(i, restoreRangeFenwick(ft0, ft1));
            
            while(qp < Q && qs[qp][1] <= i){
//                tr(qs[qp]);
                ans[qs[qp][2]] = sumRangeFenwick(ft0, ft1, qs[qp][0]);
                qp++;
            }
        }
        for(long an : ans){
            out.println(an);
        }
    }
    
    public static long sumFenwick(long[] ft, int i)
    {
        long sum = 0;
        for(i++;i > 0;i -= i&-i)sum += ft[i];
        return sum;
    }
    
    public static void addFenwick(long[] ft, int i, long v)
    {
        if(v == 0)return;
        int n = ft.length;
        for(i++;i < n;i += i&-i)ft[i] += v;
    }
    
    public static int firstGEFenwick(long[] ft, long v)
    {
        int i = 0, n = ft.length;
        for(int b = Integer.highestOneBit(n);b != 0;b >>= 1){
            if((i|b) < n && ft[i|b] < v){
                i |= b;
                v -= ft[i];
            }
        }
        return i;
    }
    
    public static long[] restoreFenwick(long[] ft)
    {
        int n = ft.length-1;
        long[] ret = new long[n];
        for(int i = 0;i < n;i++)ret[i] = sumFenwick(ft, i);
        for(int i = n-1;i >= 1;i--)ret[i] -= ret[i-1];
        return ret;
    }
    
    public static int findGFenwick(long[] ft, long v)
    {
        int i = 0;
        int n = ft.length;
        for(int b = Integer.highestOneBit(n);b != 0 && i < n;b >>= 1){
            if(i + b < n){
                int t = i + b;
                if(v >= ft[t]){
                    i = t;
                    v -= ft[t];
                }
            }
        }
        return v != 0 ? -(i+1) : i-1;
    }
    
    public static long[] buildFenwick(long[] a)
    {
        int n = a.length;
        long[] ft = new long[n+1];
        System.arraycopy(a, 0, ft, 1, n);
        for(int k = 2, h = 1;k <= n;k*=2, h*=2){
            for(int i = k;i <= n;i+=k){
                ft[i] += ft[i-h];
            }
        }
        return ft;
    }
    
    public static void addRangeFenwick(long[] ft0, long[] ft1, int i, long v)
    {
        addFenwick(ft1, i+1, -v);
        addFenwick(ft1, 0, v);
        addFenwick(ft0, i+1, v*(i+1));
    }
    
    public static void addRangeFenwick(long[] ft0, long[] ft1, int a, int b, long v)
    {
        if(a <= b){
            addFenwick(ft1, b+1, -v);
            addFenwick(ft0, b+1, v*(b+1));
            addFenwick(ft1, a, v);
            addFenwick(ft0, a, -v*a);
        }
    }
    
    public static long sumRangeFenwick(long[] ft0, long[] ft1, int i)
    {
        return sumFenwick(ft1, i) * (i+1) + sumFenwick(ft0, i);
    }
    
    public static long[] restoreRangeFenwick(long[] ft0, long[] ft1)
    {
        int n = ft0.length-1;
        long[] ret = new long[n];
        for(int i = 0;i < n;i++)ret[i] = sumRangeFenwick(ft0, ft1, i);
        for(int i = n-1;i >= 1;i--)ret[i] -= ret[i-1];
        return ret;
    }

    
    public static class SegmentTreeOverwrite {
        public int M, H, N;
        public int[] cover;
        public int I = Integer.MAX_VALUE;
        
        public SegmentTreeOverwrite(int len)
        {
            N = len;
            M = Integer.highestOneBit(Math.max(N-1, 1))<<2;
            H = M>>>1;
            cover = new int[M];
            Arrays.fill(cover, I);
            for(int i = 0;i < N;i++){
                cover[H+i] = -1;
            }
            for(int i = H-1;i >= 1;i--){
                propagate(i);
            }
        }
        
        private void propagate(int i){}
        
        public void update(int l, int r, int v){ update(l, r, v, 0, H, 1); }
        
        private void update(int l, int r, int v, int cl, int cr, int cur)
        {
            if(l <= cl && cr <= r){
                cover[cur] = v;
                propagate(cur);
            }else{
                int mid = cl+cr>>>1;
                if(cover[cur] != I){ // back-propagate
                    cover[2*cur] = cover[2*cur+1] = cover[cur];
                    cover[cur] = I;
                    propagate(2*cur);
                    propagate(2*cur+1);
                }
                if(cl < r && l < mid){
                    update(l, r, v, cl, mid, 2*cur);
                }
                if(mid < r && l < cr){
                    update(l, r, v, mid, cr, 2*cur+1);
                }
                propagate(cur);
            }
        }
        
        public int get(int x){ 
            int val = I;
            for(int i = H+x;i >= 1;i>>>=1){
                if(cover[i] != I)val = cover[i];
            }
            return val;
        }
    }

    
    public static class HeavyLightDecomposition {
        public int[] clus;
        public int[][] cluspath;
        public int[] clusiind;
        public int[] par, dep;
        
        public HeavyLightDecomposition(int[][] g, int[] par, int[] ord, int[] dep)
        {
            init(g, par, ord, dep);
        }
        
        public void init(int[][] g, int[] par, int[] ord, int[] dep)
        {
            clus = decomposeToHeavyLight(g, par, ord);
            cluspath = clusPaths(clus, ord);
            clusiind = clusIInd(cluspath, g.length);
            this.par = par;
            this.dep = dep;
        }
        
        public static int[] decomposeToHeavyLight(int[][] g, int[] par, int[] ord)
        {
            int n = g.length;
            int[] size = new int[n];
            Arrays.fill(size, 1);
            for(int i = n-1;i > 0;i--)size[par[ord[i]]] += size[ord[i]];
            
            int[] clus = new int[n];
            Arrays.fill(clus, -1);
            int p = 0;
            for(int i = 0;i < n;i++){
                int u = ord[i];
                if(clus[u] == -1)clus[u] = p++;
                // centroid path (not heavy path)
                int argmax = -1;
                for(int v : g[u]){
                    if(par[u] != v && (argmax == -1 || size[v] > size[argmax]))argmax = v;
                }
                if(argmax != -1)clus[argmax] = clus[u];
            }
            return clus;
        }
        
        public static int[][] clusPaths(int[] clus, int[] ord)
        {
            int n = clus.length;
            int[] rp = new int[n];
            int sup = 0;
            for(int i = 0;i < n;i++){
                rp[clus[i]]++;
                sup = Math.max(sup, clus[i]);
            }
            sup++;
            
            int[][] row = new int[sup][];
            for(int i = 0;i < sup;i++)row[i] = new int[rp[i]];
            
            for(int i = n-1;i >= 0;i--){
                row[clus[ord[i]]][--rp[clus[ord[i]]]] = ord[i];
            }
            return row;
        }
        
        public static int[] clusIInd(int[][] clusPath, int n)
        {
            int[] iind = new int[n];
            for(int[] path : clusPath){
                for(int i = 0;i < path.length;i++){
                    iind[path[i]] = i;
                }
            }
            return iind;
        }
        
        public int lca(int x, int y)
        {
            int rx = cluspath[clus[x]][0];
            int ry = cluspath[clus[y]][0];
            while(clus[x] != clus[y]){
                if(dep[rx] > dep[ry]){
                    x = par[rx];
                    rx = cluspath[clus[x]][0];
                }else{
                    y = par[ry];
                    ry = cluspath[clus[y]][0];
                }
            }
            return clusiind[x] > clusiind[y] ? y : x;
        }
        
        public int ancestor(int x, int v)
        {
            while(x != -1){
                if(v <= clusiind[x])return cluspath[clus[x]][clusiind[x]-v];
                v -= clusiind[x]+1;
                x = par[cluspath[clus[x]][0]];
            }
            return x;
        }
    }

    
    public static int lca2(int a, int b, int[][] spar, int[] depth) {
        if (depth[a] < depth[b]) {
            b = ancestor(b, depth[b] - depth[a], spar);
        } else if (depth[a] > depth[b]) {
            a = ancestor(a, depth[a] - depth[b], spar);
        }

        if (a == b)
            return a;
        int sa = a, sb = b;
        for (int low = 0, high = depth[a], t = Integer.highestOneBit(high), k = Integer
                .numberOfTrailingZeros(t); t > 0; t >>>= 1, k--) {
            if ((low ^ high) >= t) {
                if (spar[k][sa] != spar[k][sb]) {
                    low |= t;
                    sa = spar[k][sa];
                    sb = spar[k][sb];
                } else {
                    high = low | t - 1;
                }
            }
        }
        return spar[0][sa];
    }

    protected static int ancestor(int a, int m, int[][] spar) {
        for (int i = 0; m > 0 && a != -1; m >>>= 1, i++) {
            if ((m & 1) == 1)
                a = spar[i][a];
        }
        return a;
    }

    public static int[][] logstepParents(int[] par) {
        int n = par.length;
        int m = Integer.numberOfTrailingZeros(Integer.highestOneBit(n - 1)) + 1;
        int[][] pars = new int[m][n];
        pars[0] = par;
        for (int j = 1; j < m; j++) {
            for (int i = 0; i < n; i++) {
                pars[j][i] = pars[j - 1][i] == -1 ? -1 : pars[j - 1][pars[j - 1][i]];
            }
        }
        return pars;
    }

    
    public static int[][] parents3(int[][] g, int root) {
        int n = g.length;
        int[] par = new int[n];
        Arrays.fill(par, -1);

        int[] depth = new int[n];
        depth[0] = 0;

        int[] q = new int[n];
        q[0] = root;
        for (int p = 0, r = 1; p < r; p++) {
            int cur = q[p];
            for (int nex : g[cur]) {
                if (par[cur] != nex) {
                    q[r++] = nex;
                    par[nex] = cur;
                    depth[nex] = depth[cur] + 1;
                }
            }
        }
        return new int[][] { par, q, depth };
    }

    
    static int[][] packU(int n, int[] from, int[] to) {
        int[][] g = new int[n][];
        int[] p = new int[n];
        for (int f : from)
            p[f]++;
        for (int t : to)
            p[t]++;
        for (int i = 0; i < n; i++)
            g[i] = new int[p[i]];
        for (int i = 0; i < from.length; i++) {
            g[from[i]][--p[from[i]]] = to[i];
            g[to[i]][--p[to[i]]] = from[i];
        }
        return g;
    }
    
    public static class SuffixAutomatonOfBit {
        public Node t0;
        public int len;
        public Node[] nodes;
        public int gen;
        private boolean sortedTopologically = false;
        private boolean lexsorted = false;
        
        private SuffixAutomatonOfBit(int n)
        {
            gen = 0;
            nodes = new Node[2*n];
            this.t0 = makeNode(0, null);
        }
        
        private Node makeNode(int len, Node original)
        {
            Node node = new Node();
            node.id = gen;
            node.original = original;
            node.len = len;
            nodes[gen++] = node;
            return node;
        }
        
        public static class Node
        {
            public int id;
            public int len;
            public char key;
            public Node link;
            private Node[] next = new Node[3];
            public Node original;
            public int np = 0;
            public int hit = 0;
            
            public void putNext(char c, Node to)
            {
                to.key = c;
                if(hit<<~(c-'a')<0){
                    for(int i = 0;i < np;i++){
                        if(next[i].key == c){
                            next[i] = to;
                            return;
                        }
                    }
                }
                hit |= 1<<c-'a';
                if(np == next.length){
                    next = Arrays.copyOf(next, np*2);
                }
                next[np++] = to;
            }
            
            public boolean containsKeyNext(char c)
            {
                return hit<<~(c-'a')<0;
//                for(int i = 0;i < np;i++){
//                    if(next[i].key == c)return true;
//                }
//                return false;
            }
            
            public Node getNext(char c)
            {
                if(hit<<~(c-'a')<0){
                    for(int i = 0;i < np;i++){
                        if(next[i].key == c)return next[i];
                    }
                }
                return null;
            }
            
            public List<String> suffixes(char[] s)
            {
                List<String> list = new ArrayList<String>();
                if(id == 0)return list;
                int first = original != null ? original.len : len;
                for(int i = link.len + 1;i <= len;i++){
                    list.add(new String(s, first - i, i));
                }
                return list;
            }
        }

        public static SuffixAutomatonOfBit build(char[] str)
        {
            int n = str.length;
            SuffixAutomatonOfBit sa = new SuffixAutomatonOfBit(n);
            sa.len = str.length;
            
            Node last = sa.t0;
            for(char c : str){
                last = sa.extend(last, c);
            }
            
            return sa;
        }
        
        public Node extend(Node last, char c)
        {
            Node cur = makeNode(last.len+1, null);
            Node p;
            for(p = last; p != null && !p.containsKeyNext(c);p = p.link){
                p.putNext(c, cur);
            }
            if(p == null){
                cur.link = t0;
            }else{
                Node q = p.getNext(c); // not null
                if(p.len + 1 == q.len){
                    cur.link = q;
                }else{
                    Node clone = makeNode(p.len+1, q);
                    clone.next = Arrays.copyOf(q.next, q.next.length);
                    clone.hit = q.hit;
                    clone.np = q.np;
                    clone.link = q.link;
                    for(;p != null && q.equals(p.getNext(c)); p = p.link){
                        p.putNext(c, clone);
                    }
                    q.link = cur.link = clone;
                }
            }
            return cur;
        }
        
        public SuffixAutomatonOfBit lexSort()
        {
            for(int i = 0;i < gen;i++){
                Node node = nodes[i];
                Arrays.sort(node.next, 0, node.np, new Comparator<Node>() {
                    public int compare(Node a, Node b) {
                        return a.key - b.key;
                    }
                });
            }
            lexsorted = true;
            return this;
        }
        
        public SuffixAutomatonOfBit sortTopologically()
        {
            int[] indeg = new int[gen];
            for(int i = 0;i < gen;i++){
                for(int j = 0;j < nodes[i].np;j++){
                    indeg[nodes[i].next[j].id]++;
                }
            }
            Node[] sorted = new Node[gen];
            sorted[0] = t0;
            int p = 1;
            for(int i = 0;i < gen;i++){
                Node cur = sorted[i];
                for(int j = 0;j < cur.np;j++){
                    if(--indeg[cur.next[j].id] == 0){
                        sorted[p++] = cur.next[j];
                    }
                }
            }
            
            for(int i = 0;i < gen;i++)sorted[i].id = i;
            nodes = sorted;
            sortedTopologically = true;
            return this;
        }
        
        // visualizer
        
        public String toString()
        {
            StringBuilder sb = new StringBuilder();
            for(Node n : nodes){
                if(n != null){
                    sb.append(String.format("{id:%d, len:%d, link:%d, cloned:%b, ",
                            n.id,
                            n.len,
                            n.link != null ? n.link.id : null,
                            n.original.id));
                    sb.append("next:{");
                    for(int i = 0;i < n.np;i++){
                        sb.append(n.next[i].key + ":" + n.next[i].id + ",");
                    }
                    sb.append("}");
                    sb.append("}");
                    sb.append("\n");
                }
            }
            return sb.toString();
        }
        
        public String toGraphviz(boolean next, boolean suffixLink)
        {
            StringBuilder sb = new StringBuilder("http://chart.apis.google.com/chart?cht=gv:dot&chl=");
            sb.append("digraph{");
            for(Node n : nodes){
                if(n != null){
                    if(suffixLink && n.link != null){
                        sb.append(n.id)
                        .append("->")
                        .append(n.link.id)
                        .append("[style=dashed],");
                    }
                    
                    if(next && n.next != null){
                        for(int i = 0;i < n.np;i++){
                            sb.append(n.id)
                            .append("->")
                            .append(n.next[i].id)
                            .append("[label=")
                            .append(n.next[i].key)
                            .append("],");
                        }
                    }
                }
            }
            sb.append("}");
            return sb.toString();
        }
        
        public String label(Node n)
        {
            if(n.original != null){
                return n.id + "C";
            }else{
                return n.id + "";
            }
        }
        
        public String toDot(boolean next, boolean suffixLink)
        {
            StringBuilder sb = new StringBuilder("digraph{\n");
            sb.append("graph[rankdir=LR];\n");
            sb.append("node[shape=circle];\n");
            for(Node n : nodes){
                if(n != null){
                    if(suffixLink && n.link != null){
                        sb.append("\"" + label(n) + "\"")
                        .append("->")
                        .append("\"" + label(n.link) + "\"")
                        .append("[style=dashed];\n");
                    }
                    
                    if(next && n.next != null){
                        for(int i = 0;i < n.np;i++){
                            sb.append("\"" + label(n) + "\"")
                            .append("->")
                            .append("\"" + label(n.next[i]) + "\"")
                            .append("[label=\"")
                            .append(n.next[i].key)
                            .append("\"];\n");
                        }
                    }
                }
            }
            sb.append("}\n");
            return sb.toString();
        }
    }
    
    void run() throws Exception
    {
        is = INPUT.isEmpty() ? System.in : new ByteArrayInputStream(INPUT.getBytes());
        out = new PrintWriter(System.out);
        
        long s = System.currentTimeMillis();
        solve();
        out.flush();
        if(!INPUT.isEmpty())tr(System.currentTimeMillis()-s+"ms");
    }
    
    public static void main(String[] args) throws Exception { 
        new How_Many_Substrings().run(); 
    }
    
    private byte[] inbuf = new byte[1024];
    public int lenbuf = 0, ptrbuf = 0;
    
    private int readByte()
    {
        if(lenbuf == -1)throw new InputMismatchException();
        if(ptrbuf >= lenbuf){
            ptrbuf = 0;
            try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
            if(lenbuf <= 0)return -1;
        }
        return inbuf[ptrbuf++];
    }
    
    private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
    private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }
    
    private double nd() { return Double.parseDouble(ns()); }
    private char nc() { return (char)skip(); }
    
    private String ns()
    {
        int b = skip();
        StringBuilder sb = new StringBuilder();
        while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
            sb.appendCodePoint(b);
            b = readByte();
        }
        return sb.toString();
    }
    
    private char[] ns(int n)
    {
        char[] buf = new char[n];
        int b = skip(), p = 0;
        while(p < n && !(isSpaceChar(b))){
            buf[p++] = (char)b;
            b = readByte();
        }
        return n == p ? buf : Arrays.copyOf(buf, p);
    }
    
    private char[][] nm(int n, int m)
    {
        char[][] map = new char[n][];
        for(int i = 0;i < n;i++)map[i] = ns(m);
        return map;
    }
    
    private int[] na(int n)
    {
        int[] a = new int[n];
        for(int i = 0;i < n;i++)a[i] = ni();
        return a;
    }
    
    private int ni()
    {
        int num = 0, b;
        boolean minus = false;
        while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
        if(b == '-'){
            minus = true;
            b = readByte();
        }
        
        while(true){
            if(b >= '0' && b <= '9'){
                num = num * 10 + (b - '0');
            }else{
                return minus ? -num : num;
            }
            b = readByte();
        }
    }
    
    private long nl()
    {
        long num = 0;
        int b;
        boolean minus = false;
        while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
        if(b == '-'){
            minus = true;
            b = readByte();
        }
        
        while(true){
            if(b >= '0' && b <= '9'){
                num = num * 10 + (b - '0');
            }else{
                return minus ? -num : num;
            }
            b = readByte();
        }
    }
    
    private static void tr(Object... o) { System.out.println(Arrays.deepToString(o)); }
}
C# C++ HackerRank Solutions java cppCSharpHackerrank Solutionsjava

Post navigation

Previous post
Next post

Leave a Reply

You must be logged in to post a comment.

  • HackerRank Dynamic Array Problem Solution
  • HackerRank 2D Array – DS Problem Solution
  • Hackerrank Array – DS Problem Solution
  • Von Neumann and Harvard Machine Architecture
  • Development of Computers
©2025 THECSICENCE | WordPress Theme by SuperbThemes