結果
| 問題 |
No.650 行列木クエリ
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2019-05-02 22:27:58 |
| 言語 | C++14 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 287 ms / 2,000 ms |
| コード長 | 9,387 bytes |
| コンパイル時間 | 1,879 ms |
| コンパイル使用メモリ | 118,636 KB |
| 実行使用メモリ | 99,400 KB |
| 最終ジャッジ日時 | 2024-12-31 13:43:52 |
| 合計ジャッジ時間 | 3,482 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 1 |
| other | AC * 10 |
ソースコード
#define _USE_MATH_DEFINES
#include <cstdio>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <complex>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <bitset>
#include <numeric>
#include <limits>
#include <climits>
#include <cfloat>
#include <functional>
#include <iterator>
using namespace std;
const int MOD = 1000000007;
class Data
{
public:
// [ a b ]
// [ c d ]
long long a, b, c, d;
Data(){
a = d = 1;
b = c = 0;
}
Data(long long a, long long b, long long c, long long d){
this->a = a;
this->b = b;
this->c = c;
this->d = d;
}
Data operator*(const Data& other) const{
Data ret;
ret.a = (a * other.a + b * other.c) % MOD;
ret.b = (a * other.b + b * other.d) % MOD;
ret.c = (c * other.a + d * other.c) % MOD;
ret.d = (c * other.b + d * other.d) % MOD;
return ret;
}
};
class DelayExec
{
public:
using T1 = Data;
using T2 = Data;
// データの初期値、以下の条件を満たすこと
// uniteData(v, INIT_DATA) == v
static const T1 INIT_DATA;
// 遅延の初期値、以下の条件を満たすこと
// updateData(prev, size, INIT_DELAY) == prev
// updateDelay(x, INIT_DELAY) == x
static const T2 INIT_DELAY;
// 2つの区間の計算結果v1,v2に対して、
// その2つの区間を統合した区間における計算結果を返す
static T1 uniteData(T1 v1, T1 v2){
return v1 * v2;
}
// 長さがlenの区間における前回の計算結果prevに対して、
// 区間の各要素にパラメータxを用いた更新処理を適用した後の計算結果を返す
static T1 updateData(T1 prev, int len, T2 x){
if(x.a == -1)
return prev;
else
return x;
}
// パラメータx1,x2による2つの更新処理を順に適用した場合に対して、
// 同じ結果になるような1つの更新処理のパラメータを返す
static T2 updateDelay(T2 x1, T2 x2){
if(x2.a == -1)
return x1;
else
return x2;
}
};
const DelayExec::T1 DelayExec::INIT_DATA;
const DelayExec::T2 DelayExec::INIT_DELAY(-1, -1, -1, -1);
template <class D = DelayExec>
class SegmentTree
{
private:
using T1 = typename D::T1;
using T2 = typename D::T2;
int n;
vector<T1> data;
vector<T2> delay;
void updateTree(int a, int b, int k, int l, int r, T2 x){
if(a <= l && r <= b){
data[k] = D::updateData(data[k], r - l, x);
delay[k] = D::updateDelay(delay[k], x);
}
else if(a < r && l < b){
int len = (r - l) / 2;
for(int i=0; i<2; ++i){
data[k*2+1+i] = D::updateData(data[k*2+1+i], len, delay[k]);
delay[k*2+1+i] = D::updateDelay(delay[k*2+1+i], delay[k]);
}
delay[k] = D::INIT_DELAY;
updateTree(a, b, k*2+1, l, (l+r+1)/2, x);
updateTree(a, b, k*2+2, (l+r+1)/2, r, x);
data[k] = D::uniteData(data[k*2+1], data[k*2+2]);
}
}
T1 getValue(int a, int b, int k, int l, int r){
if(a <= l && r <= b){
return data[k];
}
else if(a < r && l < b){
int len = (r - l) / 2;
for(int i=0; i<2; ++i){
data[k*2+1+i] = D::updateData(data[k*2+1+i], len, delay[k]);
delay[k*2+1+i] = D::updateDelay(delay[k*2+1+i], delay[k]);
}
delay[k] = D::INIT_DELAY;
T1 v1 = getValue(a, b, k*2+1, l, (l+r+1)/2);
T1 v2 = getValue(a, b, k*2+2, (l+r+1)/2, r);
return D::uniteData(v1, v2);
}
else{
return D::INIT_DATA;
}
}
public:
SegmentTree(int n0){
n = 1;
while(n < n0)
n *= 2;
data.assign(2*n-1, D::INIT_DATA);
delay.assign(2*n-1, D::INIT_DELAY);
}
SegmentTree(const vector<T1>& v) : SegmentTree((int)v.size()){
for(unsigned i=0; i<v.size(); ++i)
data[n-1+i] = v[i];
for(int k=n-2; k>=0; --k)
data[k] = D::uniteData(data[k*2+1], data[k*2+2]);
}
// 区間[a,b)の要素にパラメータxによる更新処理を適用
void update(int a, int b, T2 x){
updateTree(a, b, 0, 0, n, x);
}
// 区間[a,b)の計算結果を返す
T1 get(int a, int b){
return getValue(a, b, 0, 0, n);
}
// a番目の要素をxで上書きする
void set(int a, T1 x){
getValue(a, a+1, 0, 0, n);
data[n-1+a] = x;
updateTree(a, a+1, 0, 0, n, D::INIT_DELAY);
}
};
template <class D = DelayExec>
class HeavyLightDecomposition
{
private:
using T1 = typename D::T1;
using T2 = typename D::T2;
int n;
vector<int> size, depth, parent, top, index;
SegmentTree<D> data, revData;
// 2回の深さ優先探索によりHL分解を行う
void dfs1(const vector<vector<int> >& edges, int curr, int prev)
{
size[curr] = 1;
for(int next : edges[curr]){
if(next == prev)
continue;
dfs1(edges, next, curr);
size[curr] += size[next];
}
}
void dfs2(const vector<vector<int> >& edges, int curr, int prev, int top2, int& cnt)
{
index[curr] = cnt;
++ cnt;
top[index[curr]] = index[top2];
if(prev != -1){
depth[index[curr]] = depth[index[prev]] + 1;
parent[index[curr]] = index[prev];
}
int maxSize = 0;
int next = -1;
for(int to : edges[curr]){
if(to != prev && maxSize < size[to]){
maxSize = size[to];
next = to;
}
}
if(next != -1)
dfs2(edges, next, curr, top2, cnt);
for(int to : edges[curr]){
if(to != prev && to != next)
dfs2(edges, to, curr, to, cnt);
}
}
public:
// コンストラクタ
HeavyLightDecomposition(const vector<vector<int> >& edges, int root) : data(0), revData(0)
{
n = edges.size();
int cnt = 0;
size.resize(n);
top.resize(n);
index.resize(n);
depth.assign(n, 0);
parent.assign(n, -1);
dfs1(edges, root, -1);
dfs2(edges, root, -1, root, cnt);
vector<int> size2(n);
for(int i=0; i<n; ++i)
size2[index[i]] = size[i];
size = move(size2);
data = SegmentTree<D>(n);
revData = SegmentTree<D>(n);
}
// コンストラクタ(初期値あり)
HeavyLightDecomposition(const vector<vector<int> >& edges, int root, const vector<T1>& init) : HeavyLightDecomposition(edges, root)
{
vector<T1> v1(n), v2(n);
for(int i=0; i<n; ++i){
v1[index[i]] = init[i];
v2[n-1-index[i]] = init[i];
}
data = SegmentTree<D>(v1);
revData = SegmentTree<D>(v2);
}
// a,b間のパスに対してパラメータxによる更新を適用
void updatePath(int a, int b, T2 x){
a = index[a];
b = index[b];
while(top[a] != top[b]){
int a2 = top[a];
int b2 = top[b];
if(depth[a2] < depth[b2]){
swap(a, b);
swap(a2, b2);
}
data.update(a2, a+1, x);
revData.update(n-1-a, n-a2, x);
a = parent[a2];
}
if(depth[a] > depth[b])
swap(a, b);
data.update(a, b+1, x);
revData.update(n-1-b, n-a, x);
}
// a,b間のパスの結果を取得
T1 getPath(int a, int b){
a = index[a];
b = index[b];
T1 leftVal = D::INIT_DATA;
T2 rightVal = D::INIT_DATA;
while(top[a] != top[b]){
int a2 = top[a];
int b2 = top[b];
if(depth[a2] < depth[b2]){
rightVal = D::uniteData(data.get(b2, b+1), rightVal);
b = parent[b2];
}
else{
leftVal = D::uniteData(leftVal, revData.get(n-1-a, n-a2));
a = parent[a2];
}
}
if(depth[a] > depth[b])
return D::uniteData(leftVal, D::uniteData(revData.get(n-1-b, n-a), rightVal));
else
return D::uniteData(leftVal, D::uniteData(data.get(a, b+1), rightVal));
}
};
int main()
{
int n;
cin >> n;
vector<vector<int> > edges(2*n-1);
for(int i=0; i<n-1; ++i){
int a, b;
cin >> a >> b;
edges[a].push_back(n+i);
edges[b].push_back(n+i);
edges[n+i].push_back(a);
edges[n+i].push_back(b);
}
HeavyLightDecomposition<> hl(edges, 0);
int q;
cin >> q;
while(--q >= 0){
char ope;
int i;
cin >> ope >> i;
if(ope == 'x'){
Data x;
cin >> x.a >> x.b >> x.c >> x.d;
hl.updatePath(n+i, n+i, x);
}
else{
int j;
cin >> j;
Data ans = hl.getPath(i, j);
cout << ans.a << ' ' << ans.b << ' ' << ans.c << ' ' << ans.d << endl;
}
}
return 0;
}