結果
問題 | No.650 行列木クエリ |
ユーザー | kopricky |
提出日時 | 2018-02-11 19:55:39 |
言語 | C++11 (gcc 11.4.0) |
結果 |
AC
|
実行時間 | 418 ms / 2,000 ms |
コード長 | 10,675 bytes |
コンパイル時間 | 2,466 ms |
コンパイル使用メモリ | 196,900 KB |
実行使用メモリ | 55,352 KB |
最終ジャッジ日時 | 2024-11-17 15:00:27 |
合計ジャッジ時間 | 5,267 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
5,248 KB |
testcase_01 | AC | 218 ms
15,360 KB |
testcase_02 | AC | 416 ms
53,764 KB |
testcase_03 | AC | 2 ms
5,248 KB |
testcase_04 | AC | 222 ms
15,360 KB |
testcase_05 | AC | 418 ms
53,748 KB |
testcase_06 | AC | 2 ms
5,248 KB |
testcase_07 | AC | 2 ms
5,248 KB |
testcase_08 | AC | 165 ms
15,616 KB |
testcase_09 | AC | 323 ms
55,352 KB |
testcase_10 | AC | 2 ms
5,248 KB |
ソースコード
#include <bits/stdc++.h> #define ll long long #define INF 1000000005 #define MOD 1000000007 #define EPS 1e-10 #define rep(i,n) for(int i=0;i<(int)(n);++i) #define rrep(i,n) for(int i=(int)(n)-1;i>=0;--i) #define srep(i,s,t) for(int i=(int)(s);i<(int)(t);++i) #define each(a,b) for(auto& (a): (b)) #define all(v) (v).begin(),(v).end() #define len(v) (int)(v).size() #define zip(v) sort(all(v)),v.erase(unique(all(v)),v.end()) #define cmx(x,y) x=max(x,y) #define cmn(x,y) x=min(x,y) #define fi first #define se second #define pb push_back #define show(x) cout<<#x<<" = "<<(x)<<endl #define spair(p) cout<<#p<<": "<<p.fi<<" "<<p.se<<endl #define sar(a,n) cout<<#a<<":";rep(kbrni,n)cout<<" "<<a[kbrni];cout<<endl #define svec(v) cout<<#v<<":";rep(kbrni,v.size())cout<<" "<<v[kbrni];cout<<endl #define svecp(v) cout<<#v<<":";each(kbrni,v)cout<<" {"<<kbrni.first<<":"<<kbrni.second<<"}";cout<<endl #define sset(s) cout<<#s<<":";each(kbrni,s)cout<<" "<<kbrni;cout<<endl #define smap(m) cout<<#m<<":";each(kbrni,m)cout<<" {"<<kbrni.first<<":"<<kbrni.second<<"}";cout<<endl using namespace std; typedef pair<int,int> P; typedef pair<ll,ll> pll; typedef vector<int> vi; typedef vector<vi> vvi; typedef vector<ll> vl; typedef vector<vl> vvl; typedef vector<double> vd; typedef vector<P> vp; typedef vector<string> vs; const int MAX_N = 100005; template<typename T> class mat : public vector<vector<T> > { private: int r,c; //行,列 public: int row() const { return r; } int column() const { return c; } mat(){} mat(int n,int m,T val = 0){ this->r = n,this->c = m; rep(i,n){ this->push_back(vector<T>(m,val)); } } void Set(int n){ this->r = n,this->c = n; rep(i,n){ this->push_back(vector<T>(n,0)); } rep(i,n){ (*this)[i][i] = 1; } } mat operator+(const mat& another){ if(this->r != another.r && this->c != another.c){ cout << "足し算失敗(サイズ不一致)" << endl; exit(1); } mat<T> X(this->r,this->c); rep(i,this->r){ rep(j,this->c){ X[i][j] = (*this)[i][j] + another[i][j]; } } return X; } mat operator+(const T val){ mat<T> X(this->r,this->c); rep(i,this->r){ rep(j,this->c){ X[i][j] = (*this)[i][j] + val; } } return X; } mat operator-(const mat& another){ if(this->r != another.r && this->c != another.c){ cout << "引き算失敗(サイズ不一致)" << endl; exit(1); } mat<T> X(this->r,this->c); rep(i,this->r){ rep(j,this->c){ X[i][j] = (*this)[i][j] - another[i][j]; } } return X; } mat operator-(const T val){ mat<T> X(this->r,this->c); rep(i,this->r){ rep(j,this->c){ X[i][j] = (*this)[i][j] - val; } } return X; } vector<T> operator*(const vector<T>& another){ if(this->c != (int)another.size()){ cout << "掛け算失敗(サイズ不一致)" << endl; exit(1); } vector<T> vec(this->r,0); rep(i,this->r){ rep(j,this->c){ vec[i] += (*this)[i][j] * another[j]; } } return vec; } mat operator*(const mat& another){ if(this->c != another.r){ cout << "掛け算失敗(サイズ不一致)" << endl; exit(1); } mat<T> X(this->r,another.c); rep(i,this->r){ rep(k,this->c){ rep(j,another.c){ X[i][j] = (X[i][j] + (*this)[i][k]*another[k][j]) % MOD; } } } return X; } mat operator-(){ mat<T> X(this->r,this->c); rep(i,this->r){ rep(j,this->c){ X[i][j] = -(*this)[i][j]; } } return X; } void print(){ rep(i,this->r){ rep(j,(this->c)-1){ cout << (*this)[i][j] << ","; } cout << (*this)[i][(this->c)-1] << endl; } } }; struct HLdecomposition{ struct Centroid{ int parid, pardepth, depth, sz; //親のパスのid,親のノードは親のパスの何番目,パスの深さ,属する頂点の数 Centroid(int idx, int dep, int deep, int size) : parid(idx), pardepth(dep), depth(deep), sz(size){} P Up(){ return P(parid, pardepth); } }; vector<vector<int> > G; vector<int> stsize, nxpath; vector<int> pathorder, pathid; //何番目のパスに属するか,そのパスの何番目か vector<Centroid> centroids; //パスが格納 vector<int> index; void Buildstsize(){ stack<P> s; s.push(P(0, -1)); while(!s.empty()) { P p = s.top(); s.pop(); if(stsize[p.first] != -1){ nxpath[p.first] = -1; for(int to : G[p.first]){ //親に向かう場合 if(p.second == to){ continue; } stsize[p.first] += stsize[to]; if(nxpath[p.first] == -1 || stsize[nxpath[p.first]] < stsize[to]) { nxpath[p.first] = to; } } }else{ s.push(p); stsize[p.first] = 1; for(int to : G[p.first]){ if(p.second != to){ s.push(P(to, p.first)); } } } } } void BuildPath() { stack<P> s; centroids.emplace_back(-1, -1, 0, 0); s.push(P(0, -1)); pathorder[0] = 0; while(!s.empty()) { P p = s.top(); s.pop(); pathid[p.first] = centroids[pathorder[p.first]].sz; for(int to : G[p.first]){ if(p.second == to) continue; if(to == nxpath[p.first]){ // Centroid-Pathについて pathorder[to] = pathorder[p.first]; }else{ // Centroid-Pathでないものについて pathorder[to] = (int)centroids.size(); centroids.emplace_back(pathorder[p.first], pathid[p.first], centroids[pathorder[p.first]].depth + 1,0); } s.emplace(to, p.first); } centroids[pathorder[p.first]].sz++; } } void Build_index(){ int ptr = 0; for(auto& centroid : centroids){ index.push_back(ptr); ptr += centroid.sz; } } void add_edge(int x, int y) { G[x].push_back(y), G[y].push_back(x); } void Build() { Buildstsize(); BuildPath(), Build_index(); } //idxが何番目のパスの何番目か P info(int idx) { return P(pathorder[idx], pathid[idx]); } //元の頂点のインデックスの配列上でのidを返す int get(int a) { P p = info(a); return (index[p.first] + p.second); } Centroid &operator[](int k) { return (centroids[k]); } void query(int a, int b, const function< void(int, int) > &func) { int pathidA, pathdepthA, pathidB, pathdepthB; tie(pathidA, pathdepthA) = info(a); tie(pathidB, pathdepthB) = info(b); while(pathidA != pathidB) { if(centroids[pathidA].depth > centroids[pathidB].depth) { func(index[pathidA], index[pathidA] + pathdepthA + 1); tie(pathidA, pathdepthA) = centroids[pathidA].Up(); }else{ func(index[pathidB], index[pathidB] + pathdepthB + 1); tie(pathidB, pathdepthB) = centroids[pathidB].Up(); } } if(pathdepthA > pathdepthB) swap(pathdepthA, pathdepthB); func(index[pathidA] + pathdepthA + 1, index[pathidA] + pathdepthB + 1); } HLdecomposition(int SZ) { G.resize(SZ); stsize.assign(SZ, -1); nxpath.resize(SZ); pathorder.resize(SZ); pathid.resize(SZ); } }; template<typename V> class segtree { private: int n,sz; vector<V> node; V I; public: segtree(int ag){ sz = ag; n = 1; while(n < sz){ n *= 2; } node.resize(2*n-1); rep(i,2*n-1){ node[i].Set(2); } I.Set(2); } void update(int k,V a) { k += n-1; node[k] = a; while(k>0){ k = (k-1)/2; node[k] = node[2*k+1] * node[2*k+2]; } } V query(int a,int b,int k=0,int l=0,int r=-1) { if(r < 0) r = n; if(r <= a || b <= l){ return I; } if(a <= l && r <= b){ return node[k]; }else{ V vl = query(a,b,2*k+1,l,(l+r)/2); V vr = query(a,b,2*k+2,(l+r)/2,r); return vl * vr; } } void print() { rep(i,sz){ cout << query(i,i+1) << " "; } cout << endl; } }; int depth[MAX_N]; void dfs(int u,int p,int d,HLdecomposition& hl) { vvi& G = hl.G; depth[u] = d; for(int v : G[u]){ if(v != p){ dfs(v,u,d+1,hl); } } } int get(int x,vp& eda) { int res; if(depth[eda[x].fi] < depth[eda[x].se]){ res = eda[x].se; }else{ res = eda[x].fi; } return res; } int main() { cin.tie(0); ios::sync_with_stdio(false); int n; cin >> n; HLdecomposition hl(n); vp eda(n-1); rep(i,n-1){ int a,b; cin >> a >> b; hl.add_edge(a,b); eda[i] = P(a,b); } hl.Build(); dfs(0,-1,0,hl); vi trans(n); rep(i,n){ trans[i] = hl.get(i); } int Q; cin >> Q; segtree<mat<ll> > seg(n); rep(i,Q){ char a; cin >> a; if(a == 'x'){ int b,c,d,e,f; cin >> b >> c >> d >> e >> f; mat<ll> up(2,2); up[0][0] = c,up[0][1] = d,up[1][0] = e,up[1][1] = f; seg.update(trans[get(b,eda)],up); }else{ mat<ll> ans; ans.Set(2); int b,c; cin >> b >> c; hl.query(b, c, [&](int l, int r){ ans = seg.query(l, r) * ans; }); cout << ans[0][0] << " " << ans[0][1] << " " << ans[1][0] << " " << ans[1][1] << "\n"; } } }