結果

問題 No.650 行列木クエリ
ユーザー koprickykopricky
提出日時 2018-02-11 19:55:39
言語 C++11
(gcc 11.4.0)
結果
AC  
実行時間 419 ms / 2,000 ms
コード長 10,675 bytes
コンパイル時間 2,367 ms
コンパイル使用メモリ 198,688 KB
実行使用メモリ 55,424 KB
最終ジャッジ日時 2024-04-28 19:50:06
合計ジャッジ時間 5,522 ms
ジャッジサーバーID
(参考情報)
judge1 / judge5
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
5,248 KB
testcase_01 AC 211 ms
15,488 KB
testcase_02 AC 416 ms
53,852 KB
testcase_03 AC 2 ms
5,376 KB
testcase_04 AC 223 ms
15,488 KB
testcase_05 AC 419 ms
53,844 KB
testcase_06 AC 2 ms
5,376 KB
testcase_07 AC 1 ms
5,376 KB
testcase_08 AC 160 ms
15,744 KB
testcase_09 AC 313 ms
55,424 KB
testcase_10 AC 1 ms
5,376 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

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