https://coderun.yandex.ru/problem/subscription-service?compiler=java-jackson Средняя

Решение

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.Arrays;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class Main {
    static class Subscription {
        List<List<String>> triggers;
        List<List<String>> shipments;
        Subscription(List<List<String>> triggers, List<List<String>> shipments) {
            this.triggers = triggers;
            this.shipments = shipments;
        }
    }
    
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
        String[] header = reader.readLine().split(" ");
        int n = Integer.parseInt(header[0]);
        int m = Integer.parseInt(header[1]);
        List<Subscription> subscriptions = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            String[] parts = reader.readLine().split(" ");
            int a = Integer.parseInt(parts[0]);
            int b = Integer.parseInt(parts[1]);
            List<List<String>> triggers = new ArrayList<>();
            List<List<String>> shipments = new ArrayList<>();
            for (int j = 0; j < a; j++) {
                triggers.add(Arrays.asList(parts[2 + j].split("\\\\.")));
            }
            for (int j = 0; j < b; j++) {
                shipments.add(Arrays.asList(parts[2 + a + j].split("\\\\.")));
            }
            subscriptions.add(new Subscription(triggers, shipments));
        }
        LinkedHashMap<String, ObjectNode> db = new LinkedHashMap<>();
        ObjectMapper mapper = new ObjectMapper();
        for (int i = 0; i < m; i++) {
            ObjectNode msgNode = (ObjectNode) mapper.readTree(reader.readLine());
            String traceId = msgNode.get("trace_id").asText();
            ObjectNode offerPatch = (ObjectNode) msgNode.get("offer");
            String offerId = offerPatch.get("id").asText();
            ObjectNode oldOffer = db.containsKey(offerId) ? db.get(offerId).deepCopy() : mapper.createObjectNode();
            ObjectNode existing = db.getOrDefault(offerId, mapper.createObjectNode());
            mergeObjects(existing, offerPatch, mapper);
            db.put(offerId, existing);
            ObjectNode newOffer = existing;
            List<ObjectNode> results = new ArrayList<>();
            for (int j = 0; j < subscriptions.size(); j++) {
                Subscription sub = subscriptions.get(j);
                boolean triggered = false;
                for (List<String> path : sub.triggers) {
                    JsonNode oldSub = getSubtree(oldOffer, path);
                    JsonNode newSub = getSubtree(newOffer, path);
                    if (changed(oldSub, newSub)) {
                        triggered = true;
                        break;
                    }
                }
                if (triggered) {
                    Set<String> unionPaths = new LinkedHashSet<>();
                    for (List<String> path : sub.triggers) {
                        unionPaths.add(String.join(".", path));
                    }
                    for (List<String> path : sub.shipments) {
                        unionPaths.add(String.join(".", path));
                    }
                    ObjectNode resultOffer = mapper.createObjectNode();
                    resultOffer.put("id", offerId);
                    for (String p : unionPaths) {
                        List<String> pathList = Arrays.asList(p.split("\\\\."));
                        copyPath(newOffer, resultOffer, pathList, mapper);
                    }
                    ObjectNode outNode = mapper.createObjectNode();
                    outNode.put("trace_id", traceId);
                    outNode.set("offer", resultOffer);
                    results.add(outNode);
                }
            }
            for (ObjectNode res : results) {
                writer.write(res.toString());
                writer.newLine();
            }
        }
        writer.flush();
        reader.close();
        writer.close();
    }
    
    static void mergeObjects(ObjectNode target, ObjectNode patch, ObjectMapper mapper) {
        patch.fieldNames().forEachRemaining(key -> {
            JsonNode value = patch.get(key);
            if (value.isObject()) {
                JsonNode child = target.get(key);
                if (child != null && child.isObject()) {
                    mergeObjects((ObjectNode) child, (ObjectNode) value, mapper);
                } else {
                    target.set(key, value.deepCopy());
                }
            } else {
                target.set(key, value.deepCopy());
            }
        });
    }
    
    static JsonNode getSubtree(JsonNode node, List<String> path) {
        JsonNode cur = node;
        for (String p : path) {
            if (cur == null || !cur.has(p)) return null;
            cur = cur.get(p);
        }
        return cur;
    }
    
    static boolean changed(JsonNode oldNode, JsonNode newNode) {
        if (oldNode == null && newNode == null) return false;
        if (oldNode == null || newNode == null) return true;
        return !oldNode.equals(newNode);
    }
    
    static void copyPath(JsonNode src, ObjectNode dst, List<String> path, ObjectMapper mapper) {
        if (path.isEmpty()) return;
        JsonNode curSrc = src;
        for (String p : path) {
            if (curSrc == null || !curSrc.has(p)) return;
            curSrc = curSrc.get(p);
        }
        if (curSrc == null) return;
        setPath(dst, path, curSrc.deepCopy(), mapper);
    }
    
    static void setPath(ObjectNode dst, List<String> path, JsonNode value, ObjectMapper mapper) {
        if (path.size() == 1) {
            dst.set(path.get(0), value);
            return;
        }
        String key = path.get(0);
        JsonNode child = dst.get(key);
        ObjectNode childObj;
        if (child != null && child.isObject()) {
            childObj = (ObjectNode) child;
        } else {
            childObj = mapper.createObjectNode();
            dst.set(key, childObj);
        }
        setPath(childObj, path.subList(1, path.size()), value, mapper);
    }
}