結果
| 問題 |
No.650 行列木クエリ
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2018-02-11 19:55:39 |
| 言語 | C++11(廃止可能性あり) (gcc 13.3.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 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 1 |
| other | AC * 10 |
ソースコード
#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";
}
}
}