結果

問題 No.650 行列木クエリ
ユーザー SHIJOUSHIJOU
提出日時 2020-09-29 00:00:13
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 98 ms / 2,000 ms
コード長 9,654 bytes
コンパイル時間 2,657 ms
コンパイル使用メモリ 226,364 KB
実行使用メモリ 17,564 KB
最終ジャッジ日時 2023-09-15 19:11:30
合計ジャッジ時間 3,813 ms
ジャッジサーバーID
(参考情報)
judge12 / judge14
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,380 KB
testcase_01 AC 41 ms
5,928 KB
testcase_02 AC 91 ms
16,644 KB
testcase_03 AC 2 ms
4,376 KB
testcase_04 AC 42 ms
5,888 KB
testcase_05 AC 98 ms
16,628 KB
testcase_06 AC 1 ms
4,380 KB
testcase_07 AC 2 ms
4,380 KB
testcase_08 AC 35 ms
6,204 KB
testcase_09 AC 69 ms
17,564 KB
testcase_10 AC 2 ms
4,380 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

//#define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
#define rep(i, n) for(int i=0; i<n; ++i)
#define all(v) v.begin(), v.end()
#define rall(v) v.rbegin(), v.rend()
using namespace std;
using ll = int64_t;
using ld = long double;
using P = pair<int, int>;
using vs = vector<string>;
using vi = vector<int>;
using vvi = vector<vi>;
template<class T> using PQ = priority_queue<T>;
template<class T> using PQG = priority_queue<T, vector<T>, greater<T> >;
const int INF = 0xccccccc;
const ll LINF = 0xcccccccccccccccLL;
template<typename T1, typename T2>
inline bool chmax(T1 &a, T2 b) {return a < b && (a = b, true);}
template<typename T1, typename T2>
inline bool chmin(T1 &a, T2 b) {return a > b && (a = b, true);}
template<typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p) { return is >> p.first >> p.second;}
template<typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) { return os << p.first << ' ' << p.second;}

#undef _GLIBCXX_DEBUG
string to_string(const string &s) {return '"' + s + '"';}
string to_string(const char *s) {return to_string(string(s));}
string to_string(bool b) {return b?"true":"false";}
string to_string(vector<bool> v) {
	string res = "{";
	for(int i = 0; i < int(v.size()); i++) {
		if(i) res += ", ";
		res += to_string(v[i]);
	}
	res += "}";
	return res;
}
template<size_t N>
string to_string(bitset<N> v) {
	string res;
	for(size_t i = 0; i < N; i++) res += char('0' + v[i]);
	return res;
}
template<class A, class B>
string to_string(pair<A, B>);
template<class A, class B, class C>
string to_string(tuple<A, B, C>);
template<class A, class B, class C, class D>
string to_string(tuple<A, B, C, D>);
template<class A>
string to_string(A v) {
	bool first = true;
	string res = "{";
	for(const auto &x:v) {
		if(!first) res += ", ";
		first = false;
		res += to_string(x);
	}
	res += "}";
	return res;
}
template<class A, class B>
string to_string(pair<A, B> p) {
	return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}
template<class A, class B, class C>
string to_string(tuple<A, B, C> t) {
	return "(" + to_string(get<0>(t)) + ", " + to_string(get<1>(t)) + ", " + to_string(get<2>(t)) + ")";
}
template<class A, class B, class C, class D>
string to_string(tuple<A, B, C, D> t) {
	return "(" + to_string(get<0>(t)) + ", " + to_string(get<1>(t)) + ", " + to_string(get<2>(t)) + ", " + to_string(get<3>(t)) + ")";
}
void debug_out() {cerr << endl;}
template<typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
	cerr << ' ' << to_string(H);
	debug_out(T...);
}
#ifdef LOCAL
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 822
#endif

const unsigned int mod = 1000000007;
//const unsigned int mod = 998244353;

struct mint {
	unsigned int x;
	mint():x(0) {}
	mint(int64_t x_) {
		int64_t v = int64_t(x_ % mod);
		if(v < 0) v += mod;
		x = (unsigned int)v;
	}
	static mint row(int v) {
		mint v_;
		v_.x = v;
		return v_;
	}
	mint operator-() const { return mint(-int64_t(x));}
	mint& operator+=(const mint a) {
		if ((x += a.x) >= mod) x -= mod;
		return *this;
	}
	mint& operator-=(const mint a) {
		if ((x += mod-a.x) >= mod) x -= mod;
		return *this;
	}
	mint& operator*=(const mint a) {
		uint64_t z = x;
		z *= a.x;
		x = (unsigned int)(z % mod);
		return *this;
	}
	mint operator+(const mint a) const { return mint(*this) += a;}
	mint operator-(const mint a) const { return mint(*this) -= a;}
	mint operator*(const mint a) const { return mint(*this) *= a;}
	friend bool operator==(const mint &a, const mint &b) {return a.x == b.x;}
	friend bool operator!=(const mint &a, const mint &b) {return a.x != b.x;}
	mint &operator++() {
		x++;
		if(x == mod) x = 0;
		return *this;
	}
	mint &operator--() {
		if(x == 0) x = mod;
		x--;
		return *this;
	}
	mint operator++(int) {
		mint result = *this;
		++*this;
		return result;
	}
	mint operator--(int) {
		mint result = *this;
		--*this;
		return result;
	}
	mint pow(int64_t t) const {
		mint x_ = *this, r = 1;
		while(t) {
			if(t&1) r *= x_;
			x_ *= x_;
			t >>= 1;
		}
		return r;
	}
	//for prime mod
	mint inv() const { return pow(mod-2);}
	mint& operator/=(const mint a) { return *this *= a.inv();}
	mint operator/(const mint a) {return mint(*this) /= a;}
};

istream& operator>>(istream& is, mint& a) { return is >> a.x;}
ostream& operator<<(ostream& os, const mint& a) { return os << a.x;}

template<class T>
struct SegTree {
	using FX = function<T(T, T)>;
	int n, _n;
	FX fx;
	const T ex;
	vector<T> dat;
	SegTree(int n_, FX fx_, T ex_):fx(fx_), ex(ex_), n(1), _n(n_) {
		while(n < n_) n <<= 1;
		dat.assign((n<<1)-1, ex);
	}
	SegTree(vector<T> &v, FX fx_, T ex_):fx(fx_), ex(ex_), n(1), _n(int(v.size())) {
		while(n < _n) n <<= 1;
		dat.assign((n<<1)-1, ex);
		copy(v.begin(), v.end(), dat.begin()+n-1);
		build();
	}
	inline int chld(int k) {return (k<<1)+1;}
	inline int chrd(int k) {return (k<<1)+2;}
	void set(int i, T t) {dat[i+n-1] = t;}
	void build() {
		for(int k = n-2; k >= 0; k--) dat[k] = fx(dat[chld(k)], dat[chrd(k)]);
	}
	void update(int i, T x) {
		i += n-1;
		dat[i] = x;
		while(i) {
			i = (i-1)>>1;
			dat[i] = fx(dat[chld(i)], dat[chrd(i)]);
		}
	}
	inline T query(int a, int b) {return query(a, b, 0, 0, n);}
	T query(int a, int b, int k, int l, int r) {
		if(r <= a || b <= l) return ex;
		if(a <= l && r <= b) return dat[k];
		T vl = query(a, b, chld(k), l, (l+r)>>1);
		T vr = query(a, b, chrd(k), (l+r)>>1, r);
		return fx(vl, vr);
	}
	template<class F>
	int max_right(int l, F f) {
		assert(f(ex));
		if(l == _n) return _n;
		l += n;
		T now = ex;
		do {
			while(~l&1) l >>= 1;
			if(!f(fx(now, dat[l-1]))) {
				while(l < n) {
					l <<= 1;
					if(f(fx(now, dat[l-1]))) {
						now = fx(now, dat[l++ - 1]);
					}
				}
				return l-n;
			}
			now = fx(now, dat[l++ - 1]);
		} while((l & -l) != l);
		return _n;
	}
	template<class F>
	int min_left(int r, F f) {
		assert(f(ex));
		if(r == 0) return 0;
		r += n;
		T now = ex;
		do {
			r--;
			while(r > 1 and r&1) r >>= 1;
			if(!f(fx(dat[r-1], now))) {
				while(r < n) {
					r = chld(r);
					if(f(fx(dat[r-1], now))) {
						now = fx(dat[--r], now);
					}
				}
				return r+1-n;
			}
			now = fx(dat[r-1], now);
		} while((r & -r) != r);
		return 0;
	}
	const T &operator[](int idx) const {return dat[idx+n-1];}
};

struct HLD {
	using Graph = vector<vector<int>>;
	using F = function<void(int, int)>;
	Graph G;
	vector<int> parent, heavy, depth, root, ids, sub, type, inv;
	int _n;
	HLD() {}
	HLD(int n):G(n), parent(n, -1), heavy(n, -1), depth(n), root(n, -1), ids(n), _n(n), sub(n, 1), type(n), inv(n) {}

	void add(int i, int j) {
		G[i].emplace_back(j);
		G[j].emplace_back(i);
	}
	void init(vector<int> roots = vector<int>(1, 0)) {
		int group = 0;
		int pos = 0;
		for(int rt:roots) {
			dfs(rt);
			bfs(rt, group++, pos);
		}
	}
	void dfs(int rt) {
		stack<pair<int, int>> st;
		st.emplace(rt, 0);
		while(!st.empty()) {
			int v = st.top().first;
			int &siz = st.top().second;
			if(siz < int(G[v].size())) {
				int u = G[v][siz++];
				if(u == parent[v]) continue;
				parent[u] = v;
				depth[u] = depth[v]+1;
				st.emplace(u, 0);
			}
			else {
				st.pop();
				int maxSubtree = 0;
				for(int u:G[v]) {
					if(u == parent[v]) continue;
					sub[v] += sub[u];
					if(maxSubtree < sub[u]) maxSubtree = sub[u], heavy[v] = u;
				}
			}
		}
	}
	void bfs(int rt, int group, int &pos) {
		queue<int> que({rt});
		while(!que.empty()) {
			int v = que.front();
			que.pop();
			for(int u = v; u != -1; u = heavy[u]) {
				type[u] = group;
				ids[u] = pos++;
				inv[ids[u]] = u;
				root[u] = v;
				for(int w:G[u]) {
					if(w != parent[u] and w != heavy[u]) que.emplace(w);
				}
			}
		}
	}
	//edge = false -> for_each_vertex, edge = true -> for_each_edge
	void for_each(int u, int v, const F &f, bool edge = false) {
		assert(type[u] == type[v]);
		while(true) {
			if(ids[u] > ids[v]) swap(u, v);
			if(root[u] == root[v]) {
				if(edge) {
					if(u != v) f(ids[u]+1, ids[v]+1);
				}
				else f(ids[u], ids[v]+1);
				break;
			}
			f(ids[root[v]], ids[v]+1);
			v = parent[root[v]];
		}
	}
	int lca(int u, int v) {
		while(true) {
			if(ids[u] > ids[v]) swap(u, v);
			if(root[u] == root[v]) return u;
			v = parent[root[v]];
		}
	}
	int dis(int u, int v) {
		return depth[u] + depth[v] - (depth[lca(u, v)]<<1);
	}
	const int &operator[](int i) const {return ids[i];}
};

//head

struct M {
	array<array<mint, 2>, 2> x;
	M() {}
	M(mint i) {
		x[0][0] = x[1][1] = i;
	}
	M(mint a, mint b, mint c, mint d) {
		x[0][0] = a;
		x[0][1] = b;
		x[1][0] = c;
		x[1][1] = d;
	}
	M mul(const M &u) {
		M res;
		rep(i, 2) rep(j, 2) rep(k, 2) res[i][j] += x[i][k]*u[k][j];
		return res;
	}
	array<mint, 2> &operator[](int i) {return x[i];}
	const array<mint, 2> &operator[](int i) const {return x[i];}
};
ostream &operator<<(ostream &os, const M &res) {return os << res[0][0] << ' ' << res[0][1] << ' ' << res[1][0] << ' ' << res[1][1] << '\n';}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin >> n;
	vector<P> ab(n-1);
	HLD hld(n);
	rep(i, n-1) {
		int a, b;
		cin >> a >> b;
		ab[i] = {a, b};
		hld.add(a, b);
	}
	hld.init();
	SegTree<M> seg(n, [](M a, M b)->M{return a.mul(b);}, M(1));
	int q;
	cin >> q;
	while(q--) {
		char c;
		cin >> c;
		if(c == 'x') {
			int id;
			mint a, b, c, d;
			cin >> id >> a >> b >> c >> d;
			auto [u, v] = ab[id];
			u = hld[u];
			v = hld[v];
			seg.update(max(u, v), M(a, b, c, d));
			debug(ab[id]);
		}
		else {
			int i, j;
			cin >> i >> j;
			M res(1);
			hld.for_each(i, j, [&](int i, int j)->void{res = seg.query(i, j).mul(res);}, true);
			cout << res;
		}
	}
}
0