結果

問題 No.650 行列木クエリ
ユーザー mamekinmamekin
提出日時 2019-05-02 22:27:58
言語 C++14
(gcc 13.2.0 + boost 1.83.0)
結果
AC  
実行時間 288 ms / 2,000 ms
コード長 9,387 bytes
コンパイル時間 2,278 ms
コンパイル使用メモリ 117,860 KB
実行使用メモリ 99,000 KB
最終ジャッジ日時 2023-08-30 04:54:03
合計ジャッジ時間 3,295 ms
ジャッジサーバーID
(参考情報)
judge11 / judge14
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
4,376 KB
testcase_01 AC 105 ms
22,548 KB
testcase_02 AC 282 ms
83,676 KB
testcase_03 AC 1 ms
4,376 KB
testcase_04 AC 107 ms
22,544 KB
testcase_05 AC 288 ms
83,664 KB
testcase_06 AC 1 ms
4,376 KB
testcase_07 AC 2 ms
4,376 KB
testcase_08 AC 97 ms
25,628 KB
testcase_09 AC 208 ms
99,000 KB
testcase_10 AC 2 ms
4,380 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#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;
}
0