Cerinta completa

You are given a tree with N nodes and each has a value associated with it. You are given Q queries, each of which is either an update or a retrieval operation.

Initially all node values are zero.

The update query is of the format

a1 d1 a2 d2 A B

This means you’d have to add in all nodes in the path from A to B where is the distance between the node and A.

The retrieval query is of the format

i j

You need to return the sum of the node values lying in the path from node i to node j modulo 1000000007.

Note:

  1. First all update queries are given and then all retrieval queries.
  2. Distance between 2 nodes is the shortest path length between them taking each edge weight as 1.

Input Format

The first line contains two integers (N and R respectively) separated by a space.

In the next N-1 lines, the ith line describes the ith edge: a line with two integers x y separated by a single space denotes an edge between nodes x and y.

The next line contains 2 space separated integers (U and Q respectively) representing the number of Update and Query operations to follow.

U lines follow. Each of the next U lines contains 6 space separated integers (a1,d1,a2,d2,A and B respectively).

Each of the next Q lines contains 2 space separated integers, i and j respectively.

Output Format

It contains exactly Q lines and each line containing the answer of the ith query.

Constraints

2 <= N <= 105
2 <= R <= 109
1 <= U <= 105
1 <= Q <= 105
1 <= a1,a2,d1,d2 <= 108
1 <= x, y, i, j, A, B <= N

Note
For the update operation, x can be equal to y and for the query operation, i can be equal to j.

Sample Input

7 2
1 2
1 3
2 4
2 6
4 5
6 7
1 4
1 1 1 1 4 6
4 5
2 7
4 7
5 3

Sample Output

1
44
45
9

Explanation

The node values after updation becomes :

0 8 0 1 0 36 0

Answer to Query #1: 1+0 = 1

Answer to Query #2: 8+36+0 = 44

Answer to Query #3: 1+8+36+0 = 45

Answer to Query #4: 0+1+8+0+0 = 9


Limbajul de programare folosit: cpp14

Cod:

#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include <set>
#include <map>
#include <queue>
#include <iostream>
#include <sstream>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cctype>
#include <cassert>
#include <limits>
#include <functional>
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
#define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i))
#if defined(_MSC_VER) || __cplusplus > 199711L
#define aut(r,v) auto r = (v)
#else
#define aut(r,v) __typeof(v) r = (v)
#endif
#define each(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it)
#define all(o) (o).begin(), (o).end()
#define pb(x) push_back(x)
#define mp(x,y) make_pair((x),(y))
#define mset(m,v) memset(m,v,sizeof(m))
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3fLL
using namespace std;
typedef vector<int> vi; typedef pair<int,int> pii; typedef vector<pair<int,int> > vpii; typedef long long ll;
template<typename T, typename U> inline void amin(T &x, U y) { if(y < x) x = y; }
template<typename T, typename U> inline void amax(T &x, U y) { if(x < y) x = y; }

template<int MOD>
struct ModInt {
    static const int Mod = MOD;
    unsigned x;
    ModInt(): x(0) { }
    ModInt(signed sig) { int sigt = sig % MOD; if(sigt < 0) sigt += MOD; x = sigt; }
    ModInt(signed long long sig) { int sigt = sig % MOD; if(sigt < 0) sigt += MOD; x = sigt; }
    int get() const { return (int)x; }
    
    ModInt &operator+=(ModInt that) { if((x += that.x) >= MOD) x -= MOD; return *this; }
    ModInt &operator-=(ModInt that) { if((x += MOD - that.x) >= MOD) x -= MOD; return *this; }
    ModInt &operator*=(ModInt that) { x = (unsigned long long)x * that.x % MOD; return *this; }
    ModInt &operator/=(ModInt that) { return *this *= that.inverse(); }
    
    ModInt operator+(ModInt that) const { return ModInt(*this) += that; }
    ModInt operator-(ModInt that) const { return ModInt(*this) -= that; }
    ModInt operator*(ModInt that) const { return ModInt(*this) *= that; }
    ModInt operator/(ModInt that) const { return ModInt(*this) /= that; }
    
    ModInt inverse() const {
        long long a = x, b = MOD, u = 1, v = 0;
        while(b) {
            long long t = a / b;
            a -= t * b; std::swap(a, b);
            u -= t * v; std::swap(u, v);
        }
        return ModInt(u);
    }
    ModInt operator-() const { ModInt t; t.x = x == 0 ? 0 : Mod - x; return t; }
};
typedef ModInt<1000000007> mint;

struct To {
    typedef int Vertex;
    Vertex to;
    To() { }
    To(Vertex to_): to(to_) { }
};
template<typename To_>
struct StaticGraph {
    typedef To_ To;
    typedef typename To::Vertex Vertex;
    typedef std::pair<Vertex,To> Edge;
    typedef const To *const_iterator;
 
    void init(int n_, const std::vector<Edge> &edges) {
        n = n_; int m = edges.size();
        tos.resize(m+1); offsets.resize(n+1);
        for(int e = 0; e < m; e ++) offsets[edges[e].first] ++;
        for(int v = 1; v <= n_; v ++) offsets[v] += offsets[v-1];
        for(int e = 0; e < m; e ++)
            tos[-- offsets[edges[e].first]] = edges[e].second;
    }
    int numVertices() const { return n; }
    int numEdges() const { return tos.size() - 1; }
 
    inline const_iterator edgesBegin(int v) const { return &tos[offsets[v]]; }
    inline const_iterator edgesEnd(int v) const { return &tos[offsets[v+1]]; }
private:
    int n;
    std::vector<To> tos;
    std::vector<int> offsets;
};

class SchieberVishkinLCA {
public:
    typedef StaticGraph<To> Graph;
    typedef unsigned Word;
    typedef Graph::Vertex Vertex;
private:

    static inline Word lowestOneBit(Word v) {
        return v & (~v+1);
    }
    static inline Word highestOneBitMask(Word v) {
        v |= v >> 1;
        v |= v >> 2;
        v |= v >> 4;
        v |= v >> 8;
        v |= v >> 16;
        return v >> 1;
    }

    std::vector<Word> indices;            //Vertex -> index
    std::vector<Word> maxHIndices;        //Vertex -> index
    std::vector<Word> ancestorHeights;    //Vertex -> Word
    std::vector<Vertex> pathParents;    //index-1 -> Vertex
public:
    //g
    void build(const Graph &g, Vertex root) {
        return build(g, std::vector<Vertex>(1, root));
    }
    void build(const Graph &g, const std::vector<Vertex> &roots) {
        int N = g.numVertices();

        ancestorHeights.resize(N);
        std::vector<Vertex> parents(N);
        maxHIndices.resize(N);
        std::vector<Vertex> vertices; vertices.reserve(N);
        indices.resize(N);

        //inorder traversal
        Word currentIndex = 1;
        for(int ri = 0; ri < (int)roots.size(); ri ++) {
            Vertex root = roots[ri];
            parents[root] = root;    //
            vertices.push_back(root);
        }
        while(!vertices.empty()) {
            Vertex v = vertices.back(); vertices.pop_back();
            indices[v] = currentIndex ++;
            for(const Graph::To *it = g.edgesBegin(v); it != g.edgesEnd(v); ++ it) {
                parents[it->to] = v;
                vertices.push_back(it->to);
            }
        }

        //BFS ()
        int head = 0, tail = roots.size();
        vertices.resize(N);
        for(int ri = 0; ri < (int)roots.size(); ri ++)
            vertices[ri] = roots[ri];
        while(head != tail) {
            Vertex v = vertices[head ++];
            for(const Graph::To *it = g.edgesBegin(v); it != g.edgesEnd(v); ++ it)
                vertices[tail ++] = it->to;
        }

        //
        for(std::vector<Vertex>::const_iterator it = vertices.begin(); it != vertices.end(); ++ it)
            maxHIndices[*it] = indices[*it];
        for(std::vector<Vertex>::const_reverse_iterator it = vertices.rbegin(); it != vertices.rend(); ++ it) {
            Vertex v = *it, parent = parents[v];
            if(lowestOneBit(maxHIndices[parent]) < lowestOneBit(maxHIndices[v]))
                maxHIndices[parent] = maxHIndices[v];
        }

        //A
        for(int ri = 0; ri < (int)roots.size(); ri ++) {
            Vertex root = roots[ri];
            ancestorHeights[root] = 0;
        }
        for(std::vector<Vertex>::const_iterator it = vertices.begin(); it != vertices.end(); ++ it) {
            Vertex v = *it;
            ancestorHeights[v] = ancestorHeights[parents[v]] | lowestOneBit(maxHIndices[v]);
        }

        pathParents.swap(parents);    //
        for(int ri = 0; ri < (int)roots.size(); ri ++) {
            Vertex root = roots[ri];
            pathParents[indices[root]-1] = root;
        }
        for(std::vector<Vertex>::const_iterator it = vertices.begin(); it != vertices.end(); ++ it) {
            Vertex v = *it;
            for(const Graph::To *jt = g.edgesBegin(v); jt != g.edgesEnd(v); ++ jt) {
                if(maxHIndices[v] != maxHIndices[jt->to])
                    pathParents[indices[jt->to]-1] = v;
                else
                    pathParents[indices[jt->to]-1] = pathParents[indices[v]-1];
            }
        }
    }

    Vertex query(Vertex v, Vertex u) const {
        //binary treeLCA
        Word Iv = maxHIndices[v], Iu = maxHIndices[u];
        Word hIv = lowestOneBit(Iv), hIu = lowestOneBit(Iu);
        Word hbMask = highestOneBitMask((Iv ^ Iu) | hIv | hIu);
        Word j = lowestOneBit(ancestorHeights[v] & ancestorHeights[u] & ~hbMask);
        //j = hI(lca(v,u))  (hI(x) = 2^(complete binary treeI(x)), I(x) = maxHIndices[x])
        //(hI(lca(v,u)) = j)hI(v)hI(u)
        Vertex x, y;
        if(j == hIv) x = v;
        else {            //lcav
            Word kMask = highestOneBitMask(ancestorHeights[v] & (j-1));    //vj
            x = pathParents[(indices[v] & ~kMask | (kMask+1))-1];    //indices[v]k
        }
        if(j == hIu) y = u;
        else {            //lcau
            Word kMask = highestOneBitMask(ancestorHeights[u] & (j-1));    //uj
            y = pathParents[(indices[u] & ~kMask | (kMask+1))-1];    //indices[u]k
        }
        return indices[x] < indices[y] ? x : y;    //in-order
    }
};
vector<int> t_parent;
vi t_ord;

void tree_getorder(const vector<vi> &g, int root) {
    int n = g.size();
    t_parent.assign(n, -1);
    t_ord.clear();

    vector<int> stk; stk.push_back(root);
    while(!stk.empty()) {
        int i = stk.back(); stk.pop_back();
        t_ord.push_back(i);
        for(int j = (int)g[i].size()-1; j >= 0; j --) {
            int c = g[i][j];
            if(t_parent[c] == -1 && c != root)
                stk.push_back(c);
            else
                t_parent[i] = c;
        }
    }
}

void querysub(vector<mint> &adds, int A, int B, mint x) {
    adds[A] += x;
    adds[B] -= x;
}

int main() {
    typedef StaticGraph<To> Graph;
    int N, R;
    scanf("%d%d", &N, &R);
    vector<vi> g(N);
    rep(i, N-1) {
        int x, y;
        scanf("%d%d", &x, &y), -- x, -- y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    tree_getorder(g, 0);
    vector<int> depth(N, 0);
    reu(ix, 1, N) {
        int i = t_ord[ix];
        depth[i] = depth[t_parent[i]] + 1;
    }
    vector<Graph::Edge> edges;
    reu(i, 1, N)
        edges.push_back(Graph::Edge(t_parent[i], i));
    Graph gg; gg.init(N, edges);
    SchieberVishkinLCA lca; lca.build(gg, 0);
    vector<mint> powRs(N*2+1);
    powRs[N] = 1;
    rer(i, 1, N) powRs[N+i] = powRs[N+i-1] * R;
    mint invR = mint(R).inverse();
    rer(i, 1, N) powRs[N-i] = powRs[N-i+1] * invR;
    const int T = 6;
    vector<mint> adds[T], coefs[T];
    rep(t, T) coefs[t].assign(N+1, mint());
    rep(i, N) {
        int d = depth[i];
        coefs[0][i] = powRs[N-d];
        coefs[1][i] = powRs[N+d];
        coefs[2][i] = powRs[N-d] * -d;
        coefs[3][i] = powRs[N+d] * +d;
        coefs[4][i] = powRs[N-d] * -d * -d;
        coefs[5][i] = powRs[N+d] * +d * +d;
    }
    rep(t, T) adds[t].assign(N+1, mint());
    vector<mint> values(N, mint());
    int U, Q;
    scanf("%d%d", &U, &Q);
    rep(ii, U) {
        int a1, d1, a2, d2, A, B;
        scanf("%d%d%d%d%d%d", &a1, &d1, &a2, &d2, &A, &B), -- A, -- B;
        //(a1 + z d1) (a2 + z d2) R^z
        //= a1 a2 R^z + (a1 d2 + d1 a2) z R^z + d1 d2 z^2 R^z
        int C = lca.query(A, B), Cp = C == 0 ? N : t_parent[C];
        int dA = depth[A], dB = depth[B], dC = depth[C];
        int uC = dA - dC, uB = dA + dB - dC * 2;
        mint p = powRs[N+dA], q = powRs[N-dB+uB];
        int e = -dB+uB;
        //a1 a2 R^z
        if(1) {
            mint t = mint(a1) * a2;
            querysub(adds[0], A, Cp, t * p);
            querysub(adds[1], B, C,  t * q);
        }
        //(a1 d2 + d1 a2) z R^z
        if(1) {
            mint t = mint(a1) * d2 + mint(d1) * a2;
            querysub(adds[2], A, Cp, t * p);
            querysub(adds[0], A, Cp, t * p * dA);
            querysub(adds[3], B, C,  t * q);
            querysub(adds[1], B, C,  t * q * e);
        }
        //d1 d2 z^2 R^z
        if(1) {
            mint t = mint(d1) * d2;
            querysub(adds[4], A, Cp, t * p);
            querysub(adds[2], A, Cp, t * p * dA * 2);
            querysub(adds[0], A, Cp, t * p * dA * dA);
            querysub(adds[5], B, C,  t * q);
            querysub(adds[3], B, C,  t * q * e * 2);
            querysub(adds[1], B, C,  t * q * e * e);
        }
    }
    rep(t, T) {
        for(int ix = N-1; ix > 0; -- ix) {
            int i = t_ord[ix];
            adds[t][t_parent[i]] += adds[t][i];
        }
        rep(i, N)
            adds[t][i] *= coefs[t][i];
//        cerr << t << ": "; rep(i, N) cerr << adds[t][i].get() << ", "; cerr << endl;
        rep(i, N)
            values[i] += adds[t][i];
        adds[t].assign(N+1, mint());
    }
//    cerr << "values: "; rep(i, N) cerr << values[i].get() << ", "; cerr << endl;
//    }
    vector<mint> sums = values;
    for(int ix = 1; ix < N; ++ ix) {
        int i = t_ord[ix];
        sums[i] += sums[t_parent[i]];
    }
    rep(ii, Q) {
        int A, B;
        scanf("%d%d", &A, &B), -- A, -- B;
        int C = lca.query(A, B);
        mint ans = 0;
        ans += sums[A];
        ans += sums[B];
        ans -= values[C];
        if(C != 0)
            ans -= sums[t_parent[C]] * 2;
        printf("%d\n", ans.get());
    }
    return 0;
}

Scor obtinut: 1.0

Submission ID: 464654047

Link challenge: https://www.hackerrank.com/challenges/easy-addition/problem

Easy Addition