Cerinta completa
Chinese Version
Russian Version
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.
The update query is of the format
i j X
This means you’d have to add a GP series to the nodes which lie in the path from node i to node j (both inclusive) with first term of the GP as X on node i and the common ratio as R (given in the input)
The retrieval query is of the format
i j
You need to return the sum of the node values (S) lying in the path from node i to node j modulo 100711433.
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 a b separated by a single space denotes an edge between a, b.
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 3 space separated integers (i,j, and X 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 <= 100000
2 <= R <= 109
1 <= U <= 100000
1 <= Q <= 100000
1 <= X <= 10
1 <= a, b, i, j <= N
Sample Input
6 2
1 2
1 4
2 6
4 5
4 3
2 2
1 6 3
5 3 5
6 4
5 1
Sample Output
31
18
Explanation
The node values after the first updation becomes :
3 6 0 0 0 12
The node values after second updation becomes :
3 6 20 10 5 12
Answer to Query #1: 12 + 6 + 3 + 10 = 31
Answer to Query #2: 5 + 10 +3 = 18
Limbajul de programare folosit: cpp14
Cod:
#define _CRT_SECURE_NO_WARNINGS
#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 <list>
#include <cassert>
#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
#define EPS 1e-9
using namespace std;
typedef vector<int> vi; typedef pair<int,int> pii; typedef vector<pair<int,int> > vpii;
typedef long long ll; typedef vector<long long> vl; typedef pair<long long,long long> pll; typedef vector<pair<long long,long long> > vpll;
typedef vector<string> vs; typedef long double ld;
template<typename T, typename U> inline void amin(T &x, U y) { if(x > y) x = y; }
template<typename T, typename U> inline void amax(T &x, U y) { if(x < y) x = y; }
struct CentroidPathDecomposition {
vector<int> colors, positions; //Vertex -> Color, Vertex -> Offset
vector<int> lengths, parents, branches; //Color -> Int, Color -> Color, Color -> Offset
vector<int> parentnodes, depths; //Vertex -> Vertex, Vertex -> Int
//vector<...>????1???????????????sortNodes()??????
vector<int> sortednodes, offsets; //Index -> Vertex, Color -> Index
//???????????????????????????(???)
void build(const vector<vi> &g, int root) {
int n = g.size();
colors.assign(n, -1); positions.assign(n, -1);
lengths.clear(); parents.clear(); branches.clear();
parentnodes.assign(n, -1); depths.assign(n, -1);
vector<int> subtreesizes;
measure(g, root, subtreesizes);
struct State {
int i, len, parent;
State() { }
State(int i_, int l, int p): i(i_), len(l), parent(p) { }
};
depths[root] = 0;
vector<State> s;
s.push_back(State(root, 0, -1));
while(!s.empty()) {
State t = s.back(); s.pop_back();
int i = t.i, len = t.len;
int color = lengths.size();
if(t.parent != -2) {
assert(parents.size() == color);
parents.push_back(t.parent);
branches.push_back(len);
len = 0;
}
colors[i] = color;
positions[i] = len;
int maxsize = -1, maxj = -1;
each(j, g[i]) if(colors[*j] == -1) {
if(maxsize < subtreesizes[*j]) {
maxsize = subtreesizes[*j];
maxj = *j;
}
parentnodes[*j] = i;
depths[*j] = depths[i] + 1;
}
if(maxj == -1) {
lengths.push_back(len + 1);
}else {
each(j, g[i]) if(colors[*j] == -1 && *j != maxj)
s.push_back(State(*j, len, color));
s.push_back(State(maxj, len + 1, -2));
}
}
sortNodes();
}
void sortNodes() {
int n = colors.size(), m = lengths.size();
sortednodes.resize(n, -1);
offsets.resize(m + 1);
rep(i, m) offsets[i+1] = offsets[i] + lengths[i];
rep(i, n) sortednodes[offsets[colors[i]] + positions[i]] = i;
}
void get(int v, int &c, int &p) const {
c = colors[v]; p = positions[v];
}
bool go_up(int &c, int &p) const {
p = branches[c]; c = parents[c];
return c != -1;
}
inline const int *nodesBegin(int c) const { return &sortednodes[0] + offsets[c]; }
inline const int *nodesEnd(int c) const { return &sortednodes[0] + offsets[c+1]; }
private:
void measure(const vector<vi> &g, int root, vector<int> &out_subtreesizes) const {
out_subtreesizes.assign(g.size(), -1);
vector<int> s;
s.push_back(root);
while(!s.empty()) {
int i = s.back(); s.pop_back();
if(out_subtreesizes[i] == -2) {
int s = 1;
each(j, g[i]) if(out_subtreesizes[*j] != -2)
s += out_subtreesizes[*j];
out_subtreesizes[i] = s;
}else {
s.push_back(i);
each(j, g[i]) if(out_subtreesizes[*j] == -1)
s.push_back(*j);
out_subtreesizes[i] = -2;
}
}
}
};
typedef int Vertex;
struct Graph {
typedef std::pair<Vertex, Vertex> Edge;
struct To {
Vertex to;
};
int n, m;
Graph(int n_, const std::vector<Edge> &edges):
n(n_), m(edges.size()), tos(m+1), offsets(n+1, 0) {
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]].to = edges[e].second;
}
inline const To *edgesBegin(int v) const { return &tos[offsets[v]]; }
inline const To *edgesEnd(int v) const { return &tos[offsets[v+1]]; }
inline const int outDegree(int v) const { return offsets[v+1] - offsets[v]; }
private:
std::vector<To> tos;
std::vector<int> offsets;
};
class SchieberVishkinLCA {
public:
typedef unsigned Word;
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) {
assert(g.m == g.n - 1);
ancestorHeights.resize(g.n);
std::vector<Vertex> parents(g.n);
maxHIndices.resize(g.n);
std::vector<Vertex> vertices; vertices.reserve(g.n);
indices.resize(g.n);
//euler tour
Word currentIndex = 1;
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 = 1;
vertices.resize(g.n); vertices[0] = root;
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????
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); //???????
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 tree???LCA???????
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 tree???I(x)???), I(x) = maxHIndices[x])
//(hI(lca(v,u)) = j)?hI(v)?hI(u)????????????????????????…
Vertex x, y;
if(j == hIv) x = v;
else { //lca?v????????
Word kMask = highestOneBitMask(ancestorHeights[v] & (j-1)); //v?????j???????????????????
x = pathParents[(indices[v] & ~kMask | (kMask+1))-1]; //indices[v]?k???????????
}
if(j == hIu) y = u;
else { //lca?u????????
Word kMask = highestOneBitMask(ancestorHeights[u] & (j-1)); //u?????j???????????????????
y = pathParents[(indices[u] & ~kMask | (kMask+1))-1]; //indices[u]?k???????????
}
return indices[x] < indices[y] ? x : y; //in-order????????????????????
}
};
void direct_tree(const vector<vi> &g, int i, int parent, vector<pii> &out_edges) {
each(j, g[i]) if(*j != parent) {
out_edges.pb(mp(i, *j));
direct_tree(g, *j, i, out_edges);
}
}
template<int MOD>
struct ModInt {
static const int Mod = MOD;
int x;
ModInt(): x(0) { }
ModInt(signed sig) { if((x = sig % MOD + MOD) >= MOD) x -= MOD; }
ModInt(signed long long sig) { if((x = sig % MOD + MOD) >= MOD) x -= MOD; }
int get() const { return 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);
}
bool operator==(ModInt that) const { return x == that.x; }
bool operator!=(ModInt that) const { return x != that.x; }
ModInt operator-() const { ModInt t; t.x = x == 0 ? 0 : Mod - x; return t; }
};
typedef ModInt<100711433> mint;
mint powR[100001], powinvR[100001];
mint up[100001], down[100001];
mint sum[100001];
int main() {
int N, R, invR, U, Q;
scanf("%d%d", &N, &R);
invR = mint(R).inverse().get();
powR[0] = powinvR[0] = 1;
reu(i, 1, N+1) powR[i] = powR[i-1] * R;
reu(i, 1, N+1) powinvR[i] = powinvR[i-1] * invR;
vector<vi> g(N);
rep(i, N-1) {
int a, b;
scanf("%d%d", &a, &b); a --, b --;
g[a].pb(b); g[b].pb(a);
}
vector<pii> edges;
direct_tree(g, 0, -1, edges);
CentroidPathDecomposition cpd; cpd.build(g, 0);
SchieberVishkinLCA lca; lca.build(Graph(N, edges), 0);
mset(up, 0); mset(down, 0);
scanf("%d%d", &U, &Q);
rep(ii, U) {
int a, b, X;
scanf("%d%d%d", &a, &b, &X); a --, b --;
int l = lca.query(a, b);
int c, p, lc, lp;
cpd.get(l, lc, lp);
mint x = X;
cpd.get(a, c, p);
while(1) {
int k = cpd.offsets[c], kp = k + p, k0 = k + (c == lc ? lp : 0);
up[k + p] += x;
x *= powR[kp - k0 + 1];
if(k0) up[k0 - 1] -= x;
if(c == lc) break;
cpd.go_up(c, p);
}
int len = cpd.depths[a] + cpd.depths[b] - cpd.depths[l] * 2;
x = powR[len] * X;
cpd.get(b, c, p);
while(1) {
int k = cpd.offsets[c], kp = k + p, k0 = k + (c == lc ? lp + 1 : 0);
int h = kp - k0 + 1;
mint nx = x * powinvR[h];
down[k0] += nx * R;
down[kp + 1] -= x * R;
if(c == lc) break;
x = nx;
cpd.go_up(c, p);
}
}
for(int i = N-1; i > 0; i --) up[i-1] += up[i] * R;
for(int i = 0; i < N; i ++) down[i+1] += down[i] * R;
sum[0] = 0;
rep(i, N) sum[i+1] = sum[i] + up[i] + down[i];
rep(ii, Q) {
int a, b;
scanf("%d%d", &a, &b); a --, b --;
int l = lca.query(a, b);
int c, p, lc, lp;
cpd.get(l, lc, lp);
cpd.get(a, c, p);
mint ans = 0;
while(1) {
int k = cpd.offsets[c], kp = k + p, k0 = k + (c == lc ? lp : 0);
ans += sum[kp+1] - sum[k0];
if(c == lc) break;
cpd.go_up(c, p);
}
cpd.get(b, c, p);
while(1) {
int k = cpd.offsets[c], kp = k + p, k0 = k + (c == lc ? lp + 1 : 0);
ans += sum[kp+1] - sum[k0];
if(c == lc) break;
cpd.go_up(c, p);
}
printf("%d\n", ans.get());
}
return 0;
}
Scor obtinut: 1.0
Submission ID: 464653726
Link challenge: https://www.hackerrank.com/challenges/recalling-early-days-gp-with-trees/problem
