Skip to content

Instantly share code, notes, and snippets.

@SansPapyrus683
Last active November 26, 2021 16:31
Show Gist options
  • Save SansPapyrus683/157b3db77df828a823f4213f54766261 to your computer and use it in GitHub Desktop.
Save SansPapyrus683/157b3db77df828a823f4213f54766261 to your computer and use it in GitHub Desktop.
codeforces experience sol

hi i'm back with another solution thing
whatever you like to call it

so this time it's this problem from the codeforces educational portal or whatever

so this is a standard dsu problem, except this time you need to

  1. get the value of a certain node
  2. increment all the values of a set (given by a certain node) by some value

and there's the standard linking operation but that's obvious lmao

so at first i thought about storing points in a points array and then just incrementing the root of each set when the input asked me to increment a set
then when they queried for the amt of points i could just sum up the points array for each node that was on the path from the current node to the root and win basically

but then i realized if the root already had some previous value when it was declared as the parent of another set, this would also cause the set that was merged into the parent to be incremented by what was already in the root- take the sample input for example- we have points[1] to be 100, but then when we merge node 3 into node 1, now the algorithm thinks that node 3 also has 100 points, even though it was just node 1

so we fix this by keeping an array extra_points that stores the initial value in the root and then subtract the values in the array when querying to tell all the points that were previously there when merged to frick off

also disclaimer path compression isn't used because it would mess up the algorithm
think it's still possible tho

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using std::cout;
using std::endl;
using std::vector;

class Players {
    private:
        vector<int> parents;
        vector<int> sizes;
        vector<int> points;
        vector<int> extra_points;
    public:
        Players(int size) : parents(size), sizes(size, 1),
                            points(size), extra_points(size) {
            for (int i = 0; i < size; i++) {
                parents[i] = i;
            }
        }

        int get_ultimate(int n) {
            return parents[n] == n ? n : get_ultimate(parents[n]);
        }

        int get_points(int n) {
            int amt = points[n];
            if (parents[n] == n) {
                return amt;
            }
            amt += get_points(parents[n]) - extra_points[n];
            return amt;
        }

        void add_points(int n, int p) {
            int top = get_ultimate(n);
            points[top] += p;
        }

        bool link(int n1, int n2) {
            n1 = get_ultimate(n1);
            n2 = get_ultimate(n2);
            if (n1 == n2) {
                return false;
            }
            if (sizes[n1] < sizes[n2]) {
                std::swap(n1, n2);
            }
            sizes[n1] += sizes[n2];
            parents[n2] = n1;
            extra_points[n2] = points[n1];
            return true;
        }
};

/**
 * https://codeforces.com/edu/course/2/lesson/7/1/practice/contest/289390/problem/C
 * 3 6
 * add 1 100
 * join 1 3
 * add 1 50
 * get 1
 * get 2
 * get 3 should output 150, 0, and 50, each on a new line
 */
int main() {
    int node_num;
    int query_num;
    std::cin >> node_num >> query_num;
    Players players(node_num + 1);
    for (int q = 0; q < query_num; q++) {
        std::string type;
        std::cin >> type;
        if (type == "get") {
            int n;
            std::cin >> n;  
            cout << players.get_points(n) << endl;
        } else if (type == "add") {
            int n;
            int points;
            std::cin >> n >> points;
            players.add_points(n, points);
        } else if (type == "join") {
            int a;
            int b;
            std::cin >> a >> b;
            players.link(a, b);
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment