/* -*- coding: utf-8 -*- * * 650.cc: No.650 行列木クエリ - yukicoder */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; /* constant */ const int MAX_N = 100000; const int MAX_K = 18; const int MAX_E2 = 1 << 18; const long long MOD = 1000000007; /* typedef */ typedef long long ll; typedef queue qi; typedef pair pii; typedef vector vpii; struct Mat { ll x00, x01, x10, x11; Mat(): x00(1), x01(0), x10(0), x11(1) {} Mat(ll _x00, ll _x01, ll _x10, ll _x11): x00(_x00), x01(_x01), x10(_x10), x11(_x11) {} void unit() { x00 = x11 = 1, x01 = x10 = 0; } void set(ll _x00, ll _x01, ll _x10, ll _x11) { x00 = _x00, x01 = _x01, x10 = _x10, x11 = _x11; } Mat operator*(const Mat &m) const { return Mat((x00 * m.x00 + x01 * m.x10) % MOD, (x00 * m.x01 + x01 * m.x11) % MOD, (x10 * m.x00 + x11 * m.x10) % MOD, (x10 * m.x01 + x11 * m.x11) % MOD); } void print() { printf("%lld %lld %lld %lld\n", x00, x01, x10, x11); } }; template struct SegTreeMul { int n, e2; T nodes[MAX_E2], one; SegTreeMul() {} void init(int _n, T _one) { n = _n; one = _one; for (e2 = 1; e2 < n; e2 <<= 1); fill(nodes, nodes + MAX_E2, one); } T get(int i) { return nodes[e2 - 1 + i]; } void set(int i, T v) { int j = e2 - 1 + i; nodes[j] = v; j = (j - 1) / 2; for (;;) { nodes[j] = nodes[j * 2 + 1] * nodes[j * 2 + 2]; if (j == 0) break; j = (j - 1) / 2; } } T mul_range(int r0, int r1, int k, int i0, int i1) { if (r1 <= i0 || i1 <= r0) return one; if (r0 <= i0 && i1 <= r1) return nodes[k]; int im = (i0 + i1) / 2; T v0 = mul_range(r0, r1, k * 2 + 1, i0, im); T v1 = mul_range(r0, r1, k * 2 + 2, im, i1); return v0 * v1; } T mul_range(int r0, int r1) { return mul_range(r0, r1, 0, 0, e2); } }; /* global variables */ vpii nbrs[MAX_N]; SegTreeMul st; int prts[MAX_N], peis[MAX_N], cns[MAX_N], szs[MAX_N]; int sids[MAX_N], gtvs[MAX_N], gtes[MAX_N]; /* subroutines */ /* main */ int main() { int n; scanf("%d", &n); for (int i = 0; i < n - 1; i++) { int ai, bi; scanf("%d%d", &ai, &bi); nbrs[ai].push_back(pii(bi, i)); nbrs[bi].push_back(pii(ai, i)); } prts[0] = peis[0] = -1; qi q; q.push(0); while (! q.empty()) { int u = q.front(); q.pop(); int &up = prts[u]; vpii &nbru = nbrs[u]; for (vpii::iterator vit = nbru.begin(); vit != nbru.end(); vit++) { int &v = vit->first, &ve = vit->second; if (v != up) { cns[u]++; prts[v] = u; peis[v] = ve; q.push(v); } } } //for (int i = 0; i < n; i++) printf("%d ", cns[i]); putchar('\n'); for (int i = 0; i < n; i++) { szs[i] = 1; if (cns[i] == 0) q.push(i); } while (! q.empty()) { int u = q.front(); q.pop(); int &up = prts[u]; if (up >= 0) { szs[up] += szs[u]; if (--cns[up] == 0) q.push(up); } } //for (int i = 0; i < n; i++) printf("%d ", szs[i]); putchar('\n'); for (vpii::iterator vit = nbrs[0].begin(); vit != nbrs[0].end(); vit++) q.push(vit->first); int sn = 0; while (! q.empty()) { int u = q.front(); q.pop(); int &up = prts[u], &uei = peis[u]; sids[uei] = sn++; gtvs[u] = up; gtes[u] = uei; for (int cu = u; cu >= 0;) { int &cup = prts[cu]; vpii &nbrcu = nbrs[cu]; int maxsz = 0, maxi = -1; for (vpii::iterator vit = nbrcu.begin(); vit != nbrcu.end(); vit++) { int &v = vit->first; if (v != cup && maxsz < szs[v]) maxsz = szs[v], maxi = v; } if (maxi < 0) break; for (vpii::iterator vit = nbrcu.begin(); vit != nbrcu.end(); vit++) { int &v = vit->first; if (v != cup) { if (v != maxi) q.push(v); else { int &vei = peis[v]; sids[vei] = sn++; gtvs[v] = up; gtes[v] = uei; } } } cu = maxi; } } st.init(n - 1, Mat()); int qn; scanf("%d", &qn); while (qn--) { char op[2]; scanf("%s", op); if (op[0] == 'x') { int i; ll x00, x01, x10, x11; scanf("%d%lld%lld%lld%lld", &i, &x00, &x01, &x10, &x11); //printf("x %d %lld %lld %lld %lld\n", i, x00, x01, x10, x11); Mat mi(x00, x01, x10, x11); st.set(sids[i], mi); } else { // op[0] == 'g' int i, j; scanf("%d%d", &i, &j); //printf("g %d %d\n", i, j); Mat ma; while (gtvs[i] != gtvs[j]) { Mat mi = st.mul_range(sids[gtes[j]], sids[peis[j]] + 1); ma = mi * ma; j = gtvs[j]; } if (i != j) { Mat mi = st.mul_range(sids[peis[i]] + 1, sids[peis[j]] + 1); ma = mi * ma; } ma.print(); } } return 0; }