Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package xenia.and.bit.operations;
- import java.util.ArrayDeque;
- import java.util.Queue;
- import java.util.Scanner;
- public class Main {
- private static Segment[] LEAF;
- private static int n, q;
- private static Segment TREE_ROOT;
- public static void main(String[] args) {
- // Taking Input
- Scanner scanner = new Scanner(System.in);
- n = scanner.nextInt();
- q = scanner.nextInt();
- LEAF = new Segment[n + 1];
- for (int i = 1; i <= n; i++) {
- int ai = scanner.nextInt();
- LEAF[i] = new Segment(i, i, getDigits(ai), null, null);
- }
- // Build the Segment tree and Store the root
- TREE_ROOT = buildSegmentTree(1, n);
- // Serve the query of type 1 and type 2
- for (int i = 0; i < q; i++) {
- int queryType = scanner.nextInt();
- if (queryType == 2) {
- // SUM query
- int left = scanner.nextInt();
- int right = scanner.nextInt();
- long sum = segmentQuery(TREE_ROOT, left, right);
- System.out.println(sum);
- } else if (queryType == 1) {
- // Update Query
- int l = scanner.nextInt();
- int r = scanner.nextInt();
- int x = scanner.nextInt();
- int y = scanner.nextInt();
- SegmentAlter alter = new SegmentAlter(l, r, x, y);
- TREE_ROOT.addAlter(alter);
- segmentUpdtae(TREE_ROOT);
- }
- }
- scanner.close();
- }
- private static Segment buildSegmentTree(int left, int right) {
- if (left == right) {
- return LEAF[left];
- }
- // Build left segment
- Segment leftSegment = buildSegmentTree(left, (left + right) / 2);
- // Build right segment
- Segment rightSegment = buildSegmentTree((left + right) / 2 + 1, right);
- int digits[][] = new int[10][10];
- for (int i = 0; i < 10; i++) {
- for (int j = 0; j < 10; j++) {
- digits[i][j] = leftSegment.digits[i][j] + rightSegment.digits[i][j];
- }
- }
- Segment segment = new Segment(left, right, digits, leftSegment, rightSegment);
- return segment;
- }
- private static long segmentQuery(Segment segment, int left, int right) {
- if (left > right || segment == null) {
- return 0;
- }
- if ((right < segment.left || left > segment.right)) {
- return 0;
- }
- if (left <= segment.left && right >= segment.right) {
- segment.settleDownAlters();
- return segment.getSum();
- }
- if (segment.hasAlters()) {
- segment.settleDownAlters();
- }
- // Calculate the left child
- long leftSum = segmentQuery(segment.leftChild, left, right);
- // Calculate the right child
- long rightSum = segmentQuery(segment.rightChild, left, right);
- return leftSum + rightSum;
- }
- private static int[][] segmentUpdtae(Segment segment) {
- if (!segment.hasAlters()) {
- return segment.digits;
- }
- SegmentAlter recentAlter = segment.lazyAlters.getLast();
- if (segment.left >= recentAlter.left && segment.right <= recentAlter.right) {
- segment.settleDownAlters();
- return segment.digits;
- }
- // Push the alters to both the children
- segment.pushDownAlters();
- // Update left segment
- int[][] leftDigitis = segmentUpdtae(segment.leftChild);
- // Update right segment
- int[][] rightDigitis = segmentUpdtae(segment.rightChild);
- // Update digit of current segment
- int[][] newDigits = new int[10][10];
- for (int i = 0; i < 10; i++) {
- for (int j = 0; j < 10; j++)
- newDigits[i][j] = leftDigitis[i][j] + rightDigitis[i][j];
- }
- segment.digits = newDigits;
- return newDigits;
- }
- private static int[][] getDigits(int number) {
- int[][] digits = new int[10][10];
- for (int i = 0; i < 10 && number != 0; i++) {
- int digit = number % 10;
- digits[i][digit]++;
- number /= 10;
- }
- return digits;
- }
- static class Segment {
- private static final long MULTIPLIER[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
- 1000000000 };
- // Defines the bound of this segment
- public int left, right;
- // Stores the digit counts of 0~9, for different places
- public int[][] digits = new int[10][10];
- // Stores the alter query affecting this node.
- ArrayDeque<SegmentAlter> lazyAlters = new ArrayDeque<>();
- public Segment leftChild, rightChild;
- public Segment(int left, int right, int[][] digits, Segment leftChild, Segment rightChild) {
- this.left = left;
- this.right = right;
- this.digits = digits;
- this.leftChild = leftChild;
- this.rightChild = rightChild;
- }
- public boolean isLeaf() {
- return left == right;
- }
- public void addAlter(SegmentAlter alter) {
- if (this.left > alter.right || this.right < alter.left) {
- return;
- }
- this.lazyAlters.add(alter);
- }
- public void addAlters(Queue<SegmentAlter> alters) {
- alters.forEach(alter -> addAlter(alter));
- }
- public void clearAlters() {
- this.lazyAlters.clear();
- }
- public boolean hasAlters() {
- return !this.lazyAlters.isEmpty();
- }
- public void settleDownAlters() {
- // Apply the alters on the current Node
- this.lazyAlters.forEach(alter -> {
- for (int i = 0; i < 10; i++) {
- digits[i][alter.alterTo] += digits[i][alter.alterfrom];
- digits[i][alter.alterfrom] = 0;
- }
- });
- if (!isLeaf()) {
- this.leftChild.addAlters(this.lazyAlters);
- this.rightChild.addAlters(this.lazyAlters);
- }
- this.clearAlters();
- }
- public void pushDownAlters() {
- if (!isLeaf()) {
- this.leftChild.addAlters(this.lazyAlters);
- this.rightChild.addAlters(this.lazyAlters);
- }
- this.clearAlters();
- }
- public long getSum() {
- long sum = 0;
- for (int i = 0; i < 10; i++) {
- for (int j = 0; j < 10; j++) {
- sum += j * MULTIPLIER[i] * digits[i][j];
- }
- }
- return sum;
- }
- }
- static class SegmentAlter {
- // Defines the left and right of digit alter
- public int left, right;
- public int alterfrom, alterTo;
- public SegmentAlter(int left, int right, int alterfrom, int alterTo) {
- this.left = left;
- this.right = right;
- this.alterfrom = alterfrom;
- this.alterTo = alterTo;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement