static long queryRangeSum(int currNode, int tSI, int tEI, int rSI, int rEI) { Node temp = tree[currNode]; /* System.out.println("Q-----currNode : " + currNode + ", tSI : " + tSI + ", tEI : " + tEI + ", tree[cN].sum : " + tree[currNode].sum);*/ if (temp.init != -1) { // System.out.println("currNode : " + currNode + ", in init"); temp.sum = ((tEI - tSI + 1) * temp.init); temp.sum %= mod; if (tSI != tEI) { tree[2 * currNode].init = temp.init; tree[2 * currNode + 1].init = temp.init; } temp.init = -1; temp.add = 0; temp.mul = 0; } else { temp.sum = (temp.sum * temp.mul) + ((tEI - tSI + 1) * temp.add); temp.sum %= mod; if (tSI != tEI) { tree[2 * currNode].add += temp.add; tree[2 * currNode].add %= mod; tree[2 * currNode].mul *= temp.mul; tree[2 * currNode].mul %= mod; tree[2 * currNode + 1].add += temp.add; tree[2 * currNode + 1].add %= mod; tree[2 * currNode + 1].mul *= temp.mul; tree[2 * currNode + 1].mul %= mod; } temp.add = 0; temp.mul = 1; } if (tSI > tEI || tSI > rEI || tEI < rSI) return -1; if (tSI >= rSI && tEI <= rEI) return temp.sum; int mid = (tSI + tEI) / 2; long lCS, rCS; lCS = queryRangeSum(2 * currNode, tSI, mid, rSI, rEI); rCS = queryRangeSum(2 * currNode + 1, mid + 1, tEI, rSI, rEI); if (lCS == -1) lCS = 0; if (rCS == -1) rCS = 0; tree[currNode].sum = tree[2 * currNode].sum + tree[2 * currNode + 1].sum; tree[currNode].sum %= mod; return (lCS + rCS) % mod; }

static void addToRange( int currNode, int tSI, int tEI, int rSI, int rEI, long addValue) // fine, I guess { Node temp = tree[currNode]; if (temp.add > 0 || temp.mul > 1) { temp.sum = (temp.sum * temp.mul) + ((tEI - tSI + 1) * temp.add); temp.sum %= mod; if (tSI != tEI) { tree[2 * currNode].add += temp.add; tree[2 * currNode].add %= mod; tree[2 * currNode].mul *= temp.mul; tree[2 * currNode].mul %= mod; tree[2 * currNode + 1].add += temp.add; tree[2 * currNode + 1].add %= mod; tree[2 * currNode + 1].mul *= temp.mul; tree[2 * currNode + 1].mul %= mod; } temp.add = 0; temp.mul = 1; } if (tSI > tEI || tSI > rEI || tEI < rSI) return; if (tSI >= rSI && tEI <= rEI) { temp.sum = temp.sum * temp.mul + ((tEI - tSI + 1) * addValue); temp.sum %= mod; if (tSI != tEI) { tree[2 * currNode].add += addValue; tree[2 * currNode].add %= mod; tree[2 * currNode].mul *= temp.mul; tree[2 * currNode].mul %= mod; tree[2 * currNode + 1].add += addValue; tree[2 * currNode + 1].add %= mod; tree[2 * currNode + 1].mul *= temp.mul; tree[2 * currNode + 1].mul %= mod; } temp.mul = 1; return; } int mid = (tSI + tEI) / 2; addToRange(2 * currNode, tSI, mid, rSI, rEI, addValue); addToRange(2 * currNode + 1, mid + 1, tEI, rSI, rEI, addValue); temp.sum = tree[2 * currNode].sum + tree[2 * currNode + 1].sum; temp.sum %= mod; }

static void multiplyToRange(int currNode, int tSI, int tEI, int rSI, int rEI, long mulValue) { Node temp = tree[currNode]; /* System.out.println("MUL currNode : " + currNode + ", tSI : " + tSI + ", tEI : " + tEI + ", sum : " + temp.sum + ", mul : " + temp.mul); */ if (temp.mul > 1 || temp.add > 0) { temp.sum = temp.sum * temp.mul + temp.add; temp.sum %= mod; // System.out.println("mul done. sum : " + temp.sum); if (tSI != tEI) { tree[2 * currNode].mul *= temp.mul; tree[2 * currNode].mul %= mod; tree[2 * currNode].add *= temp.mul; tree[2 * currNode].add %= mod; tree[2 * currNode + 1].mul *= temp.mul; tree[2 * currNode + 1].mul %= mod; tree[2 * currNode + 1].add *= temp.mul; tree[2 * currNode + 1].add %= mod; } temp.mul = 1; temp.add = 0; } if (tSI > tEI || tSI > rEI || tEI < rSI) return; if (tSI >= rSI && tEI <= rEI) { temp.sum = temp.sum * mulValue + temp.add * mulValue; temp.sum %= mod; /* System.out.println("fully inside, sum : " + temp.sum + ", tSI : " + tSI + ", tEI : " + tEI);*/ if (tSI != tEI) { tree[2 * currNode].mul *= mulValue; tree[2 * currNode].mul %= mod; tree[2 * currNode + 1].mul *= mulValue; tree[2 * currNode + 1].mul %= mod; } temp.add = 0; // not needed // temp.mul = 1; return; } int mid = (tSI + tEI) / 2; multiplyToRange(2 * currNode, tSI, mid, rSI, rEI, mulValue); multiplyToRange(2 * currNode + 1, mid + 1, tEI, rSI, rEI, mulValue); temp.sum = tree[2 * currNode].sum + tree[2 * currNode + 1].sum; temp.sum %= mod; }

static void initializeRange(int currNode, int tSI, int tEI, int rSI, int rEI, long initValue) { Node temp = tree[currNode]; if (temp.init != -1) { temp.sum = ((tEI - tSI + 1) * temp.init); temp.sum %= mod; if (tSI != tEI) { tree[2 * currNode].init = temp.init; tree[2 * currNode + 1].init = temp.init; } temp.init = -1; temp.add = 0; temp.mul = 1; } else if (temp.add > 0 || temp.mul > 1) { temp.sum = temp.sum * temp.mul + ((tEI - tSI + 1) * temp.add); temp.sum %= mod; if (tSI != tEI) { tree[2 * currNode].add += temp.add; tree[2 * currNode].add %= mod; tree[2 * currNode + 1].add += temp.add; tree[2 * currNode + 1].add %= mod; tree[2 * currNode].mul *= temp.mul; tree[2 * currNode].mul %= mod; tree[2 * currNode + 1].mul *= temp.mul; tree[2 * currNode + 1].mul %= mod; } temp.init = -1; temp.add = 0; temp.mul = 1; } /* System.out.println("INIT cN : " + currNode + ", tSI : " + tSI + ", tEI : " + tEI + ", rSI : " + rSI + ", rEI : " + rEI);*/ if (tSI > tEI || tSI > rEI || tEI < rSI) return; if (tSI >= rSI && tEI <= rEI) { temp.sum = (tEI - tSI + 1) * initValue; temp.sum %= mod; if (tSI != tEI) { tree[2 * currNode].init = initValue; tree[2 * currNode + 1].init = initValue; } temp.add = 0; temp.mul = 1; return; } int mid = (tSI + tEI) / 2; initializeRange(2 * currNode, tSI, mid, rSI, rEI, initValue); initializeRange(2 * currNode + 1, mid + 1, tEI, rSI, rEI, initValue); tree[currNode].sum = tree[2 * currNode].sum + tree[2 * currNode + 1].sum; tree[currNode].sum %= mod; }