Problem:
H Tree Queries
問題文
umgくんは、 $N$ 頂点の木を持っています。頂点 $i \ (1\leq i \leq N)$ の重みは $v_i$ です。 $j \ (1 \leq j \leq N-1)$ 番目の辺は、頂点 $a_i$ と頂点 $b_i$ を結び、その重みは $w_i$ です。さらに、木全体の重みを「 $\sum_{1\leq a \lt b \leq N} \mathrm{dist}(a,b) v_a v_b$ を $998244353$ で割った余り」で定めます。 (15:05 更新) 
ここで、 $\mathrm{dist}(a,b)$ というのは、頂点 $a$ から頂点 $b$ の最短経路上に存在する辺の重みの和を表しています。
umgくんはまず、今持っている木全体の重みを知りたいです。さらに、 $Q$ 個の変更クエリが与えられます。クエリの種類は以下の2つです。
頂点クエリ : 頂点 $c \ (1\leq c \leq N)$ の重みを $x$ 増やす。その後、現在の木全体の重みを出力する。
辺クエリ : 辺 $e \ (1\leq e \leq N-1)$ の重みを $x$ 増やす。その後、現在の木全体の重みを出力する。
これらのクエリを処理してください。
入力
入力は以下の形式で標準入力から与えられる。
$N$
$v_1$ $v_2$ $\cdots$ $v_N$
$a_1$ $b_1$ $w_1$
$a_2$ $b_2$ $w_2$
$\vdots$
$a_{N-1}$ $b_{N-1}$ $w_{N-1}$
$Q$
$query_1$
$query_2$
$\vdots$
$query_Q$
$query_i$の入力形式は以下の2つのいずれかである。
頂点クエリ
$1$ $c$ $x$
辺クエリ
$2$ $e$ $x$
制約
入力はすべて整数である。
$1 \leq N \leq 2 \times 10^5$
$1 \leq v_i \leq 10^8 \ (1\leq i \leq N)$
$1 \leq Q \leq 10^5$
$1 \leq a_i,b_i \leq N$
$1 \leq w_i \leq 10^8 \ (1\leq i \leq N-1)$
与えられるグラフは木である。
クエリ1の$c$は$1\leq c \leq N$を満たす。
クエリ2の$e$は$1\leq e \leq N-1$を満たす。
クエリ1,2の$x$は$1\leq x \leq 10^8$を満たす。
クエリ1の数は20000以下である。
出力
答えを $Q+1$ 行に出力せよ。$1$行目には木の最初の状態で木全体の重み、$i+1$行目には、$i$番目の変更クエリ後の木全体の重みを出力せよ。
入力例1
3
1 2 4
1 2 1
2 3 2
2
1 1 1
2 2 2
出力例1
30
44
76
例えば、木の最初の状態の木全体の重みは、 $\mathrm{dist}(1,2) \times 1 \times 2 + \mathrm{dist}(1,3) \times 1 \times 4 + \mathrm{dist}(2,3) \times 2 \times 4 = 2+12+16=30$ です。
入力例2
4
2 2 3 3
1 2 4
1 3 3
1 4 1
3
2 3 4
1 4 1
2 1 10
出力例2
148
232
284
464

Submitted solutions:

code_snippet: // verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=3179

#include <bits/stdc++.h>
using namespace std;

#define call_from_test
template<typename T, T MOD = 1000000007>
struct Mint{
  inline static constexpr T mod = MOD;
  T v;
  Mint():v(0){}
  Mint(signed v):v(v){}
  Mint(long long t){v=t%MOD;if(v<0) v+=MOD;}

  Mint pow(long long k){
    Mint res(1),tmp(v);
    while(k){
      if(k&1) res*=tmp;
      tmp*=tmp;
      k>>=1;
    }
    return res;
  }

  static Mint add_identity(){return Mint(0);}
  static Mint mul_identity(){return Mint(1);}

  Mint inv(){return pow(MOD-2);}

  Mint& operator+=(Mint a){v+=a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator-=(Mint a){v+=MOD-a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator*=(Mint a){v=1LL*v*a.v%MOD;return *this;}
  Mint& operator/=(Mint a){return (*this)*=a.inv();}

  Mint operator+(Mint a) const{return Mint(v)+=a;}
  Mint operator-(Mint a) const{return Mint(v)-=a;}
  Mint operator*(Mint a) const{return Mint(v)*=a;}
  Mint operator/(Mint a) const{return Mint(v)/=a;}

  Mint operator+() const{return *this;}
  Mint operator-() const{return v?Mint(MOD-v):Mint(v);}

  bool operator==(const Mint a)const{return v==a.v;}
  bool operator!=(const Mint a)const{return v!=a.v;}

  static Mint comb(long long n,int k){
    Mint num(1),dom(1);
    for(int i=0;i<k;i++){
      num*=Mint(n-i);
      dom*=Mint(i+1);
    }
    return num/dom;
  }
};
template<typename T, T MOD>
ostream& operator<<(ostream &os,Mint<T, MOD> m){os<<m.v;return os;}

template<typename Vertex, typename Cluster, size_t N>
struct TopTree{
  enum Type { Compress, Rake, Edge };
  struct Node{
    Vertex* vs[2];
    Cluster dat;
    Node* p;
    Node* q;
    Node* ch[2];
    bool rev,guard;
    Type type;
    Node():p(nullptr),q(nullptr),rev(false),guard(false){}
  };

  inline static array<Vertex, 2*N> pool_vertex;
  inline static size_t ptr_vertex = 0;

  inline static array<Node, 4*N> pool_node;
  inline static size_t ptr_node = 0;

  Cluster id;

  template<typename ...Args>
  inline Vertex* create(Args ...args){
    auto t=&pool_vertex[ptr_vertex++];
    auto dummy=&pool_vertex[ptr_vertex++];
    *t=Vertex(forward<Args>(args)...);
    link(t,id,dummy);
    return t;
  }

  Node* recycle=nullptr;
  inline void dispose_node(Node* t){
    t->p=recycle;
    recycle=t;
  }

  inline Node* get_new_node(){
    if(recycle) return new(exchange(recycle,recycle->p)) Node;
    return &(pool_node[ptr_node++]);
  }

  inline Node* edge(Vertex* u,Cluster w,Vertex* v){
    auto t=get_new_node();
    t->vs[0]=u;t->vs[1]=v;t->dat=w;t->type=Type::Edge;
    return pushup(t);
  }

  inline Node* compress(Node* l,Node* r){
    auto t=get_new_node();
    t->ch[0]=l;t->ch[1]=r;t->type=Type::Compress;
    return pushup(t);
  }

  inline Node* rake(Node* l,Node* r){
    auto t=get_new_node();
    t->ch[0]=l;t->ch[1]=r;t->type=Type::Rake;
    return pushup(t);
  }

  int parent_dir(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->guard) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  int parent_dir_ignore_guard(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  inline Node* pushup(Node* const t){
    Node* const l=t->ch[0];
    Node* const r=t->ch[1];

    if(t->type==Type::Compress){
      assert(l->vs[1]==r->vs[0]);
      t->vs[0]=l->vs[0];
      t->vs[1]=r->vs[1];

      Cluster lf=l->dat;
      if(t->q){
        assert(l->vs[1]==t->q->vs[1]);
        lf=Cluster::rake(l->dat,t->q->dat);
      }
      t->dat=Cluster::compress(lf,r->vs[0],r->dat);

      l->vs[1]->handle=t;
    }

    if(t->type==Type::Rake){
      propagate(t);
      assert(l->vs[1]==r->vs[1]);
      t->vs[0]=l->vs[0];
      t->vs[1]=l->vs[1];
      t->dat=Cluster::rake(l->dat,r->dat);
    }else{
      if(!t->p){
        t->vs[0]->handle=t;
        t->vs[1]->handle=t;
      }else if(t->p->type==Type::Compress){
        if(parent_dir(t)==-1)
          t->vs[0]->handle=t;
      }else if(t->p->type==Type::Rake){
        t->vs[0]->handle=t;
      }
    }
    return t;
  }

  inline void toggle(Node* t){
    if(t->type==Type::Edge){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
    }else if(t->type==Type::Compress){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
      t->rev^=true;
    }else if(t->type==Type::Rake){
    }else abort();
  }

  inline void propagate(Node* t){
    if(t->type==Type::Compress){
      if(t->rev){
        assert(t->ch[0] and t->ch[1]);
        swap(t->ch[0],t->ch[1]);
        toggle(t->ch[0]);
        toggle(t->ch[1]);
        t->rev=false;
      }
    }
  }

  void set_toggle(Node* v){
    toggle(v);propagate(v);
  }

  void pushdown(Node* t){
    if(!t) return;
    pushdown(t->p);
    propagate(t);
  }

  void rotate(Node* t,Node* x,size_t dir){
    Node* y=x->p;
    int par=parent_dir_ignore_guard(x);
    propagate(t->ch[dir]);
    x->ch[dir^1]=t->ch[dir];
    t->ch[dir]->p=x;
    t->ch[dir]=x;
    x->p=t;
    t->p=y;
    if(~par) y->ch[par]=t;
    else if(y and y->type==Type::Compress) y->q=t;
    pushup(x);pushup(t);
    if(y and !y->guard) pushup(y);
  }

  void splay(Node* t){
    assert(t->type!=Type::Edge);
    propagate(t);

    while(~parent_dir(t)){
      Node* q=t->p;
      if(q->type!=t->type) break;
      if(~parent_dir(q) and q->p and q->p->type==q->type){
        Node* r=q->p;
        if(r->p) propagate(r->p);
        propagate(r);propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        int rq_dir=parent_dir(q);
        if(rq_dir==qt_dir){
          rotate(q,r,rq_dir^1);
          rotate(t,q,qt_dir^1);
        }else{
          rotate(t,q,qt_dir^1);
          rotate(t,r,rq_dir^1);
        }
      }else{
        if(q->p) propagate(q->p);
        propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        rotate(t,q,qt_dir^1);
      }
    }
  }

  Node* expose(Node* t){
    pushdown(t);
    while(true){
      assert(t->type!=Type::Rake);
      if(t->type==Type::Compress) splay(t);
      Node* n=nullptr;
      {
        Node* p=t->p;
        if(!p) break;
        if(p->type==Type::Rake){
          propagate(p);
          splay(p);
          n=p->p;
        }
        if(p->type==Type::Compress){
          propagate(p);
          if(p->guard and ~parent_dir_ignore_guard(t)) break;
          n=p;
        }
      }
      splay(n);
      int dir=parent_dir_ignore_guard(n);
      if(dir==-1 or n->p->type==Type::Rake) dir=0;

      Node* const c=n->ch[dir];
      if(dir==1){
        set_toggle(c);
        set_toggle(t);
      }
      int n_dir=parent_dir(t);
      if(~n_dir){
        Node* const r=t->p;
        propagate(c);
        propagate(r);
        r->ch[n_dir]=c;
        c->p=r;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(r);pushup(t);pushup(n);
        splay(r);
      }else{
        propagate(c);
        n->q=c;
        c->p=n;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(t);pushup(n);
      }
      if(t->type==Type::Edge) t=n;
    }
    return t;
  }

  Node* expose(Vertex* v){
    return expose((Node*)(v->handle));
  }

  void soft_expose(Vertex* u,Vertex* v){
    pushdown((Node*)u->handle);
    pushdown((Node*)v->handle);
    Node* rt=expose(u);

    if(u->handle==v->handle){
      if(rt->vs[1]==u or rt->vs[0]==v)
        set_toggle(rt);
      return;
    }

    rt->guard=true;
    Node* soft=expose(v);
    rt->guard=false;

    pushup(rt);
    if(parent_dir(soft)==0) set_toggle(rt);
  }

  void bring(Node* rt){
    Node* rk=rt->q;
    if(!rk){
      Node* ll=rt->ch[0];
      dispose_node(ll->p);
      ll->p=nullptr;
      pushup(ll);
    }else if(rk->type==Type::Compress or rk->type==Type::Edge){
      Node* nr=rk;
      set_toggle(nr);
      rt->ch[1]=nr;
      nr->p=rt;
      rt->q=nullptr;

      pushup(nr);pushup(rt);
    }else if(rk->type==Type::Rake){
      propagate(rk);
      while(rk->ch[1]->type==Type::Rake){
        propagate(rk->ch[1]);
        rk=rk->ch[1];
      }
      pushdown(rk);

      rt->guard=true;
      splay(rk);
      rt->guard=false;

      Node* ll=rk->ch[0];
      Node* rr=rk->ch[1];
      propagate(ll);
      set_toggle(rr);

      rt->ch[1]=rr;
      rr->p=rt;

      rt->q=ll;
      ll->p=rt;

      dispose_node(rk);
      pushup(ll);pushup(rr);pushup(rt);
    }
  }

  Node* link(Vertex* u,Cluster w,Vertex* v){
    if(!u->handle and !v->handle) return edge(u,w,v);

    Node* nnu=(Node*)u->handle;
    Node* nnv=(Node*)v->handle;
    Node* ee=edge(u,w,v);
    Node* ll=nullptr;

    assert(nnv);
    Node* vv=expose(nnv);
    propagate(vv);
    if(vv->vs[1]==v) set_toggle(vv);
    if(vv->vs[0]==v){
      Node* nv=compress(ee,vv);
      ee->p=nv;
      pushup(ee);
      vv->p=nv;
      pushup(vv);pushup(nv);
      ll=nv;
    }else{
      Node* nv=vv;
      Node* ch=nv->ch[0];
      propagate(ch);
      nv->ch[0]=ee;
      ee->p=nv;
      pushup(ee);

      Node* bt=nv->q;
      Node* rk=nullptr;
      if(bt){
        propagate(bt);
        rk=rake(bt,ch);
        bt->p=rk;
        ch->p=rk;
        pushup(bt);pushup(ch);
      }else{
        rk=ch;
      }
      nv->q=rk;
      rk->p=nv;
      pushup(rk);pushup(nv);
      ll=nv;
    }

    assert(nnu);
    Node* uu=expose(nnu);
    propagate(uu);
    if(uu->vs[0]==u) set_toggle(uu);
    if(uu->vs[1]==u){
      Node* tp=compress(uu,ll);
      uu->p=tp;
      ll->p=tp;
      pushup(uu);pushup(ll);pushup(tp);
    }else{
      Node* nu=uu;
      Node* ch=nu->ch[1];
      toggle(ch);
      propagate(ch);

      nu->ch[1]=ll;
      ll->p=nu;
      pushup(ll);

      Node* al=nu->q;
      Node* rk=nullptr;
      if(al){
        propagate(al);
        rk=rake(al,ch);
        al->p=rk;
        ch->p=rk;
        pushup(al);pushup(ch);
      }else{
        rk=ch;
      }
      nu->q=rk;
      rk->p=nu;
      pushup(rk);pushup(nu);
    }
    return ee;
  }

  void cut(Vertex* u,Vertex *v){
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    Node* rr=rt->ch[1];
    rr->p=nullptr;
    set_toggle(rr);
    assert(rr->ch[1]->type==Type::Edge);
    dispose_node(rr->ch[1]);
    bring(rr);bring(rt);
  }

  Node* path(Vertex* u,Vertex* v){
    assert(u!=v);
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    propagate(rt->ch[1]);
    return rt->ch[1]->ch[0];
  }

  void set_vertex(Vertex* u,Vertex v){
    auto t=expose(u);
    *u=v;
    pushup(t);
  }

  void set_edge(Vertex* u,Vertex* v,const Cluster &w){
    auto t=path(u,v);
    assert(t->type==Type::Edge);
    t->dat=w;
    while(t) pushup(t),t=t->p;
  }

  Cluster get_path(Vertex* u,Vertex* v){
    return path(u,v)->dat;
  }

  Cluster get_subtree(Vertex* v){
    return expose(v)->dat;
  }

  // subtree of v when p is root
  Cluster get_subtree(Vertex* p,Vertex* v){
    Node* t=path(p,v);
    Cluster res=t->p->ch[1]->dat;
    res.toggle();
    Node* rk=t->p->q;
    if(t->p->q){
      assert(rk->vs[1]==t->p->ch[1]->vs[0]);
      res=Cluster::rake(res,rk->dat);
    }
    return res;
  }
};

#undef call_from_test
using M = Mint<int, 998244353>;

struct Vertex{
  M v;
  void* handle;
  Vertex():v(0),handle(nullptr){}
  Vertex(M v):v(v),handle(nullptr){}
};

struct Cluster{
  M len;
  M sum_v;
  M sum_l,sum_r;
  M rake_v,rake_d;
  Cluster(M len=M(0)):len(len),sum_v(0),sum_l(0),sum_r(0),rake_v(0),rake_d(0){}
  void toggle(){
    swap(sum_l,sum_r);
  }
  static Cluster compress(Cluster x,Vertex *v,Cluster y){
    Cluster nxt(x.len+y.len);
    nxt.sum_v=x.sum_v+x.rake_v+(v->v)+y.sum_v;
    nxt.sum_l=x.sum_l+x.rake_d+y.sum_l+(x.sum_v+(v->v)+x.rake_v)*y.len;
    nxt.sum_r=x.sum_r+x.rake_d+y.sum_r+(y.sum_v+(v->v)+x.rake_v)*x.len;
    return nxt;
  }
  static Cluster rake(Cluster x,Cluster y){
    x.rake_v+=y.sum_v+y.rake_v;
    x.rake_d+=y.sum_l+y.rake_d;
    return x;
  }
};

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  const char newl ='\n';

  int n;
  cin>>n;

  vector<M> vs(n);
  for(int i=0;i<n;i++) cin>>vs[i].v;

  vector<int> as(n),bs(n);
  vector<M> ws(n);
  for(int i=1;i<n;i++){
    cin>>as[i]>>bs[i]>>ws[i].v;
    as[i]--;bs[i]--;
  }

  const size_t N = 2e5;
  TopTree<Vertex, Cluster, N> G;

  vector<Vertex*> ptr(n);
  for(int i=0;i<n;i++) ptr[i]=G.create(vs[i]);

  for(int i=1;i<n;i++)
    G.link(ptr[as[i]],Cluster(0),ptr[bs[i]]);

  M ans{0};
  for(int i=1;i<n;i++){
    Cluster x=G.get_subtree(ptr[bs[i]],ptr[as[i]]);
    Cluster y=G.get_subtree(ptr[as[i]],ptr[bs[i]]);
    ans+=ws[i]*(x.sum_v+x.rake_v+vs[as[i]])*(y.sum_v+y.rake_v+vs[bs[i]]);
    G.set_edge(ptr[as[i]],ptr[bs[i]],Cluster(ws[i]));
  }
  cout<<ans<<newl;

  Vertex* rt=G.create(Vertex(0));

  int q;
  cin>>q;
  for(int i=0;i<q;i++){
    int t;
    cin>>t;
    if(t==1){
      int c,a;
      cin>>c>>a;
      c--;
      G.link(rt,Cluster(0),ptr[c]);
      Cluster x=G.get_subtree(rt,ptr[c]);
      G.cut(rt,ptr[c]);
      ans+=M(a)*(x.sum_l+x.rake_d);
      vs[c]+=M(a);
      G.set_vertex(ptr[c],Vertex(vs[c]));
    }

    if(t==2){
      int e,a;
      cin>>e>>a;

      Cluster x=G.get_subtree(ptr[bs[e]],ptr[as[e]]);
      Cluster y=G.get_subtree(ptr[as[e]],ptr[bs[e]]);
      ans+=M(a)*(x.sum_v+x.rake_v+vs[as[e]])*(y.sum_v+y.rake_v+vs[bs[e]]);

      ws[e]+=M(a);
      G.set_edge(ptr[as[e]],ptr[bs[e]],Cluster(ws[e]));
    }
    cout<<ans<<newl;
  }
  return 0;
}
accuracy: 1
time_ms: 1370
memory_kb: 79596
final_rank: 10

code_snippet: //#define _GLIBCXX_DEBUG

#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define lfs cout<<fixed<<setprecision(10)
#define ALL(a)  (a).begin(),(a).end()
#define ALLR(a)  (a).rbegin(),(a).rend()
#define spa << " " <<
#define fi first
#define se second
#define MP make_pair
#define MT make_tuple
#define PB push_back
#define EB emplace_back
#define rep(i,n,m) for(ll i = (n); i < (ll)(m); i++)
#define rrep(i,n,m) for(ll i = (ll)(m) - 1; i >= (ll)(n); i--)
using ll = long long;
using ld = long double;
const ll MOD1 = 1e9+7;
const ll MOD9 = 998244353;
const ll INF = 1e18;
using P = pair<ll, ll>;
template<typename T> using PQ = priority_queue<T>;
template<typename T> using QP = priority_queue<T,vector<T>,greater<T>>;
template<typename T1, typename T2>bool chmin(T1 &a,T2 b){if(a>b){a=b;return true;}else return false;}
template<typename T1, typename T2>bool chmax(T1 &a,T2 b){if(a<b){a=b;return true;}else return false;}
ll median(ll a,ll b, ll c){return a+b+c-max({a,b,c})-min({a,b,c});}
void ans1(bool x){if(x) cout<<"Yes"<<endl;else cout<<"No"<<endl;}
void ans2(bool x){if(x) cout<<"YES"<<endl;else cout<<"NO"<<endl;}
void ans3(bool x){if(x) cout<<"Yay!"<<endl;else cout<<":("<<endl;}
template<typename T1,typename T2>void ans(bool x,T1 y,T2 z){if(x)cout<<y<<endl;else cout<<z<<endl;}  
template<typename T1,typename T2,typename T3>void anss(T1 x,T2 y,T3 z){ans(x!=y,x,z);};  
template<typename T>void debug(const T &v,ll h,ll w,string sv=" "){for(ll i=0;i<h;i++){cout<<v[i][0];for(ll j=1;j<w;j++)cout<<sv<<v[i][j];cout<<endl;}};
template<typename T>void debug(const T &v,ll n,string sv=" "){if(n!=0)cout<<v[0];for(ll i=1;i<n;i++)cout<<sv<<v[i];cout<<endl;};
template<typename T>void debug(const vector<T>&v){debug(v,v.size());}
template<typename T>void debug(const vector<vector<T>>&v){for(auto &vv:v)debug(vv,vv.size());}
template<typename T>void debug(stack<T> st){while(!st.empty()){cout<<st.top()<<" ";st.pop();}cout<<endl;}
template<typename T>void debug(queue<T> st){while(!st.empty()){cout<<st.front()<<" ";st.pop();}cout<<endl;}
template<typename T>void debug(deque<T> st){while(!st.empty()){cout<<st.front()<<" ";st.pop_front();}cout<<endl;}
template<typename T>void debug(PQ<T> st){while(!st.empty()){cout<<st.top()<<" ";st.pop();}cout<<endl;}
template<typename T>void debug(QP<T> st){while(!st.empty()){cout<<st.top()<<" ";st.pop();}cout<<endl;}
template<typename T>void debug(const set<T>&v){for(auto z:v)cout<<z<<" ";cout<<endl;}
template<typename T>void debug(const multiset<T>&v){for(auto z:v)cout<<z<<" ";cout<<endl;}
template<typename T,size_t size>void debug(const array<T, size> &a){for(auto z:a)cout<<z<<" ";cout<<endl;}
template<typename T,typename V>void debug(const map<T,V>&v){for(auto z:v)cout<<"["<<z.first<<"]="<<z.second<<",";cout<<endl;}
template<typename T>vector<vector<T>>vec(ll x, ll y, T w){vector<vector<T>>v(x,vector<T>(y,w));return v;}
ll gcd(ll x,ll y){ll r;while(y!=0&&(r=x%y)!=0){x=y;y=r;}return y==0?x:y;}
vector<ll>dx={1,-1,0,0,1,1,-1,-1};vector<ll>dy={0,0,1,-1,1,-1,1,-1};
template<typename T>vector<T> make_v(size_t a,T b){return vector<T>(a,b);}
template<typename... Ts>auto make_v(size_t a,Ts... ts){return vector<decltype(make_v(ts...))>(a,make_v(ts...));}
template<typename T1, typename T2>ostream &operator<<(ostream &os, const pair<T1, T2>&p){return os << p.first << " " << p.second;}
template<typename T>ostream &operator<<(ostream &os, const vector<T> &v){for(auto &z:v)os << z << " ";cout<<"|"; return os;}
template<typename T>void rearrange(vector<int>&ord, vector<T>&v){
  auto tmp = v;
  for(int i=0;i<tmp.size();i++)v[i] = tmp[ord[i]];
}
template<typename Head, typename... Tail>void rearrange(vector<int>&ord,Head&& head, Tail&&... tail){
  rearrange(ord, head);
  rearrange(ord, tail...);
}
template<typename T> vector<int> ascend(const vector<T>&v){
  vector<int>ord(v.size());iota(ord.begin(),ord.end(),0);
  sort(ord.begin(),ord.end(),[&](int i,int j){return v[i]<v[j];});
  return ord;
}
template<typename T> vector<int> descend(const vector<T>&v){
  vector<int>ord(v.size());iota(ord.begin(),ord.end(),0);
  sort(ord.begin(),ord.end(),[&](int i,int j){return v[i]>v[j];});
  return ord;
}
ll FLOOR(ll n,ll div){return n>=0?n/div:(n-div+1)/div;}
ll CEIL(ll n,ll div){return n>=0?(n+div-1)/div:n/div;}
ll digitsum(ll n){ll ret=0;while(n){ret+=n%10;n/=10;}return ret;}
template<typename T>T min(const vector<T>&v){return *min_element(v.begin(),v.end());}
template<typename T>T max(const vector<T>&v){return *max_element(v.begin(),v.end());}
template<typename T>T acc(const vector<T>&v){return accumulate(v.begin(),v.end(),T(0));};
template<typename T>T reverse(const T &v){return T(v.rbegin(),v.rend());};
//mt19937 mt(chrono::steady_clock::now().time_since_epoch().count());
int popcount(ll x){return __builtin_popcountll(x);};
int poplow(ll x){return __builtin_ctzll(x);};
int pophigh(ll x){return 63 - __builtin_clzll(x);};
template<typename T>T poll(queue<T> &q){auto ret=q.front();q.pop();return ret;};
template<typename T>T poll(priority_queue<T> &q){auto ret=q.top();q.pop();return ret;};
template<typename T>T poll(QP<T> &q){auto ret=q.top();q.pop();return ret;};
template<typename T>T poll(stack<T> &s){auto ret=s.top();s.pop();return ret;};
template< typename T = int >
struct edge {
  int to;
  T cost;
  int id;
  edge():id(-1){};
  edge(int to, T cost = 1, int id = -1):to(to), cost(cost), id(id){}
  operator int() const { return to; }
};

template<typename T>
using Graph = vector<vector<edge<T>>>;
template<typename T>
Graph<T>revgraph(const Graph<T> &g){
  Graph<T>ret(g.size());
  for(int i=0;i<g.size();i++){
    for(auto e:g[i]){
      int to = e.to;
      e.to = i;
      ret[to].push_back(e);
    }
  }
  return ret;
}
template<typename T>
Graph<T> readGraph(int n,int m,int indexed=1,bool directed=false,bool weighted=false){
  Graph<T> ret(n);
  for(int es = 0; es < m; es++){
    int u,v;
    T w=1;
    cin>>u>>v;u-=indexed,v-=indexed;
    if(weighted)cin>>w;
    ret[u].emplace_back(v,w,es);
    if(!directed)ret[v].emplace_back(u,w,es);
  }
  return ret;
}
template<typename T>
Graph<T> readParent(int n,int indexed=1,bool directed=true){
  Graph<T>ret(n);
  for(int i=1;i<n;i++){
    int p;cin>>p;
    p-=indexed;
    ret[p].emplace_back(i);
    if(!directed)ret[i].emplace_back(p);
  }
  return ret;
}
template< int mod >
struct ModInt {
  int x;

  ModInt() : x(0) {}

  ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}

  ModInt &operator+=(const ModInt &p) {
    if((x += p.x) >= mod) x -= mod;
    return *this;
  }

  ModInt &operator-=(const ModInt &p) {
    if((x += mod - p.x) >= mod) x -= mod;
    return *this;
  }

  ModInt &operator*=(const ModInt &p) {
    x = (int) (1LL * x * p.x % mod);
    return *this;
  }

  ModInt &operator/=(const ModInt &p) {
    *this *= p.inverse();
    return *this;
  }

  ModInt operator-() const { return ModInt(-x); }

  friend ModInt operator+(const ModInt& lhs, const ModInt& rhs) {
        return ModInt(lhs) += rhs;
  }
  friend ModInt operator-(const ModInt& lhs, const ModInt& rhs) {
        return ModInt(lhs) -= rhs;
  }
  friend ModInt operator*(const ModInt& lhs, const ModInt& rhs) {
        return ModInt(lhs) *= rhs;
  }
  friend ModInt operator/(const ModInt& lhs, const ModInt& rhs) {
        return ModInt(lhs) /= rhs;
  }

  bool operator==(const ModInt &p) const { return x == p.x; }

  bool operator!=(const ModInt &p) const { return x != p.x; }

  ModInt inverse() const {
    int a = x, b = mod, u = 1, v = 0, t;
    while(b > 0) {
      t = a / b;
      swap(a -= t * b, b);
      swap(u -= t * v, v);
    }
    return ModInt(u);
  }

  ModInt pow(int64_t n) const {
    ModInt ret(1), mul(x);
    while(n > 0) {
      if(n & 1) ret *= mul;
      mul *= mul;
      n >>= 1;
    }
    return ret;
  }

  friend ostream &operator<<(ostream &os, const ModInt &p) {
    return os << p.x;
  }

  friend istream &operator>>(istream &is, ModInt &a) {
    int64_t t;
    is >> t;
    a = ModInt< mod >(t);
    return (is);
  }

  static int get_mod() { return mod; }
};
using modint = ModInt< MOD9 >;modint pow(ll n, ll x){return modint(n).pow(x);}modint pow(modint n, ll x){return n.pow(x);}
//using modint=ld;
template< typename Monoid, typename OperatorMonoid,typename F, typename G, typename H>
struct LazySegmentTree {
  ll sz, height, n;
  vector< Monoid > data;
  vector< OperatorMonoid > lazy;
  const F f;
  const G g;
  const H h;
  Monoid M1;
  OperatorMonoid OM0;
  LazySegmentTree(ll n, const F &f,const G &g, const H &h, Monoid M1, OperatorMonoid OM0):n(n),f(f),g(g),h(h),M1(M1),OM0(OM0){
    sz = 1;
    height = 0;
    while(sz < n) sz <<= 1, height++;
    data.assign(2 * sz, M1);
    lazy.assign(2 * sz, OM0);
  }

  void set(ll k, const Monoid &x) {
    data[k + sz] = x;
  }

  void build() {
    for(ll k = sz - 1; k > 0; k--) {
      data[k] = f(data[2 * k + 0], data[2 * k + 1]);
    }
  }

  inline void propagate(ll k) {
    if(lazy[k] != OM0) {
      lazy[2 * k + 0] = h(lazy[2 * k + 0], lazy[k]);
      lazy[2 * k + 1] = h(lazy[2 * k + 1], lazy[k]);
      data[k] = reflect(k);
      lazy[k] = OM0;
    }
  }

  inline Monoid reflect(ll k) {
    return lazy[k] == OM0 ? data[k] : g(data[k], lazy[k]);
  }

  inline void recalc(ll k) {
    while(k >>= 1) data[k] = f(reflect(2 * k + 0), reflect(2 * k + 1));
  }

  inline void thrust(ll k) {
    for(ll i = height; i > 0; i--) propagate(k >> i);
  }

  void update(ll a, ll b, const OperatorMonoid &x) {
	if(a>=b)return;
    thrust(a += sz);
    thrust(b += sz - 1);
    for(ll l = a, r = b + 1; l < r; l >>= 1, r >>= 1) {
      if(l & 1) lazy[l] = h(lazy[l], x), ++l;
      if(r & 1) --r, lazy[r] = h(lazy[r], x);
    }
    recalc(a);
    recalc(b);
  }
  
  void update(ll a,const Monoid &x){
    thrust(a += sz);
    data[a] = x;
    lazy[a] = OM0;
    recalc(a);
  }

  Monoid query(ll a, ll b) {
	if(a>=b)return M1;
    thrust(a += sz);
    thrust(b += sz - 1);
    Monoid L = M1, R = M1;
    for(ll l = a, r = b + 1; l < r; l >>= 1, r >>= 1) {
      if(l & 1) L = f(L, reflect(l++));
      if(r & 1) R = f(reflect(--r), R);
    }
    return f(L, R);
  }

  Monoid operator[](const ll &k) {
    return query(k, k + 1);
  }

  template< typename C >
  ll find_subtree(ll a, const C &check, Monoid &M, bool type) {
    while(a < sz) {
      propagate(a);
      Monoid nxt = type ? f(reflect(2 * a + type), M) : f(M, reflect(2 * a + type));
      if(check(nxt)) a = 2 * a + type;
      else M = nxt, a = 2 * a + 1 - type;
    }
    return a - sz;
  }

  template< typename C >
  ll find_first(ll a, const C &check) {
    Monoid L = M1;
    if(a <= 0) {
      if(check(f(L, reflect(1)))) return find_subtree(1, check, L, false);
      return -1;
    }
    thrust(a + sz);
    ll b = sz;
    for(a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
      if(a & 1) {
        Monoid nxt = f(L, reflect(a));
        if(check(nxt)) return find_subtree(a, check, L, false);
        L = nxt;
        ++a;
      }
    }
    return -1;
  }


  template< typename C >
  ll find_last(ll b, const C &check) {
    Monoid R = M1;
    if(b >= sz) {
      if(check(f(reflect(1), R))) return find_subtree(1, check, R, true);
      return -1;
    }
    thrust(b + sz - 1);
    ll a = sz;
    for(b += sz; a < b; a >>= 1, b >>= 1) {
      if(b & 1) {
        Monoid nxt = f(reflect(--b), R);
        if(check(nxt)) return find_subtree(b, check, R, true);
        R = nxt;
      }
    }
    return -1;
  }
  void print(){
    for(ll i=0;i<n;i++)if((*this)[i]==M1)cout<<"x|";else cout<<(*this)[i]<<"|";
    cout<<endl;
  }
};
template<typename T>
struct HLD{
  using D=long long;
  int n;
  vector<int>sz;//部分木サイズ
  vector<D>dep;
  vector<int>par;
  vector<int>head;
  Graph<T> &g;//隣接リスト
  vector<edge<T>>edges;//データ構造に乗せるedge列
  vector<int>in,out;//[in,out)で部分木、[ina,inb]でa~bのパス(aが上)
  vector<int>comp;//連結成分の根
  //inは頂点のindexを表す。また、edge列の下側の頂点である
  HLD(Graph<T> &g,int r=-1):g(g),n(g.size()){
    hld_build(r);
  }
  void hld_build(int root = -1){
    in.assign(n,-1);out.assign(n,-1);dep.assign(n,0);
    par.assign(n,-1);head.assign(n,-1);sz.assign(n,-1);comp.assign(n,-1);
    edges.assign(n,edge<T>());
    if(root == -1){//根がどこでも良い場合(森でも可)
      for(int i=0;i<n;i++){
        if(sz[i] == -1){
          head[i] = i;
          dfs_sz(i, 0, i);
          dfs_hld(i);
        }
      }
    }
    else{
      head[root] = root;
      dfs_sz(root, 0, root);
      dfs_hld(root);
    }
  }
  void dfs_sz(int k, D d,int r){
    sz[k] = 1;
    comp[k] = r;
	dep[k] = d;
    for(auto &e: g[k]){
      if(e.to == par[k])continue;
      par[e.to] = k;
      dfs_sz(e.to, d+e.cost, r);
      sz[k] += sz[e.to];
      if(sz[e.to] > sz[g[k][0].to])swap(e, g[k][0]);
    }
  }
  int time = 0;
  void dfs_hld(int k){
    in[k] = time++;
    for(auto e:g[k]){
      if(e.to == par[k])continue;
      head[e.to] = (e.to == g[k][0].to ? head[k]: e.to);
      edges[time] = e;
      dfs_hld(e.to);
    }
    out[k] = time;
  }
  int lca(int p,int q){
    while(1){
      if(in[p] < in[q])swap(p,q);
      if(head[p] == head[q])return q;
      p = par[head[p]];
    }
  }
  vector<pair<int,int>>query_path(int p,int q,bool isEdge){
    int r=lca(p,q);
    vector<pair<int,int>>ret;
    for(int i=0;i<2;i++){
      if(i == 1)swap(p,q);
      while(1){
        if(isEdge&&p==r)break;
        if(head[p]==head[r]){
          ret.emplace_back(in[r]+(isEdge?1:i),in[p]+1);
          break;
        }
        ret.emplace_back(in[head[p]],in[p]+1);
        p = par[head[p]];
      }
    }
    return ret;
  }
  vector<vector<pair<int,int>>>query_order_path(int p,int q,bool isEdge){
	//非可換クエリ用、配列0を順番を反転したデータ構造に、配列1を通常のデータ構造に
    vector<vector<pair<int,int>>>ret(2);
    int r=lca(p,q);
    for(int i=0;i<2;i++){
      if(i == 1)swap(p,q);
      while(1){
        if(isEdge&&p==r)break;
        if(head[p]==head[r]){
          if(i==0) ret[i].emplace_back(n-(in[p]+1),n-(in[r]+(isEdge?1:i)));
          else ret[i].emplace_back(in[r]+(isEdge?1:i),in[p]+1);
          break;
        }
        if(i==0) ret[i].emplace_back(n-(in[p]+1),n-(in[head[p]]));
        else ret[i].emplace_back(in[head[p]],in[p]+1);
        p = par[head[p]];
      }
    }
    reverse(ret[1].begin(), ret[1].end());
    return ret;
  }
  pair<int,int>query_subtree(int p,bool isEdge){
    return make_pair(in[p]+isEdge,out[p]);
  }
  //uのv方向の子 子孫関係は前もって確認すること(in,outを見る)
  int child(int u,int v){
    while(1){
      if(head[u]==head[v]){
        v=g[u][0].to;
        break;
      }
      v=head[v];
      if(par[v]==u)break;
      v=par[v];
    }
    return v;
  }
  //uをv方向に一つ進めた頂点
  int move(int u,int v){
    assert(u!=v);
    if(in[u]<in[v]&&in[v]<out[u])return child(u,v);
    else return par[u];
  }
  D dist(int u,int v){
    return dep[u]+dep[v]-2*dep[lca(u,v)];
  }
  vector<int>rev_in;
  int climb(int u,int k){
    if(rev_in.empty()){
      rev_in.resize(n);
      for(int i=0;i<n;i++)rev_in[in[i]]=i;
    }
    int nd=max<int>(dep[u]-k, 0);
    while(dep[u]>nd){
      if(dep[head[u]]>nd){
        u=par[head[u]];
      }
      else{
        u=rev_in[in[head[u]]+nd-dep[head[u]]];
      }
    }
    return u;
  }
  template<typename I>
  Graph<T>lca_tree(vector<I>&v){
    auto compare=[&](int x,int y){return in[x]<in[y];};
    sort(v.begin(),v.end(),compare);
    int sz1=v.size();
    for(int i=0;i<sz1-1;i++)v.push_back(lca(v[i],v[i+1]));
    sort(v.begin(),v.end(),compare);
    v.erase(unique(v.begin(),v.end()),v.end());
    int sz2=v.size();
    Graph<T>ret(sz2);
    stack<int>st;
    for(int i=0;i<sz2;i++){
      while(!st.empty()&&out[v[st.top()]]<=in[v[i]])st.pop();
      if(!st.empty())ret[st.top()].emplace_back(i,dep[v[i]]-dep[v[st.top()]]);
      st.push(i);
    }
    return ret;
  }
};
namespace add_sum{
  struct M{
    modint vs,es,sum,sz;
  };
  using PM=pair<modint,modint>;
  auto f=[](M x,M y)->M{
    return {x.vs+y.vs,x.es+y.es,x.sum+y.sum,x.sz+y.sz};
  };
  auto g=[](M x,PM y)->M{
    return {x.vs+x.sz*y.fi,
    x.es+x.sz*y.se,
    x.sum+x.vs*y.se+x.es*y.fi+x.sz*y.fi*y.se,
    x.sz};
  };
  auto h=[](PM x,PM y)->PM{
    return MP(x.fi+y.fi,x.se+y.se);
  };
  LazySegmentTree<M,PM,decltype(f),decltype(g),decltype(h)>make(int n){
    return {n,f,g,h,{0,0,0,0},MP(0,0)};
  }
}
int main(){
  cin.tie(nullptr);
  ios_base::sync_with_stdio(false);
  ll res=0,buf=0;
  bool judge = true;
  ll n;cin>>n;
  vector<ll>vw(n);
  rep(i,0,n)cin>>vw[i];
  auto g=readGraph<int>(n,n-1,1,false,true);
  HLD hld(g);
  auto up=add_sum::make(n);
  auto down=add_sum::make(n);
  auto ord=ascend(hld.in);
  vector<ll>epos(n-1);
  up.build();
  down.build();
  modint ret=0;
  modint allsz=0;
  rep(i,0,n)allsz+=vw[i];
  vector<modint>subsz(n,0);
  {
    auto dfs=[&](auto &&f,ll k,ll par)->void{
      subsz[k]=vw[k];
      for(auto to:g[k]){
        if(to==par)continue;
        f(f,to,k);
        subsz[k]+=subsz[to];
      }
    };
    dfs(dfs,0,-1);
  }
  rep(i,1,n){
    modint sz=subsz[ord[i]];
    epos[hld.edges[i].id]=i;
    up.set(i,{allsz-sz,hld.edges[i].cost,(allsz-sz)*hld.edges[i].cost,1});
    down.set(i,{sz,hld.edges[i].cost,sz*hld.edges[i].cost,1});
    ret+=hld.edges[i].cost*sz*(allsz-sz);
  }
  up.build();
  down.build();
  cout<<ret<<endl;
  ll q;cin>>q;
  while(q--){
    ll t,k,w;cin>>t>>k>>w;k--;
    if(t==1){
      modint add=down.query(1,n).sum;
      auto tmp=hld.query_path(0,k,true);
      //cout<<q spa add spa k spa tmp.size()<<endl;
      for(auto z:tmp){
        add-=down.query(z.fi,z.se).sum;
        //cout<<q spa add<<endl;
        add+=up.query(z.fi,z.se).sum;
        //cout<<q spa add<<endl;
      }
      ret+=add*w;
      up.update(1,n,MP(w,0));
      for(auto z:tmp){
        up.update(z.fi,z.se,MP(-w,0));
        down.update(z.fi,z.se,MP(w,0));
      }
      vw[k]+=w;
      allsz+=w;
    }
    if(t==2){
      modint sz=down[epos[k]].vs;
      ret+=sz*(allsz-sz)*w;
      up.update(epos[k],epos[k]+1,MP(0,w));
      down.update(epos[k],epos[k]+1,MP(0,w));
    }
    cout<<ret<<endl;
  }
  return 0;
}
accuracy: 1
time_ms: 460
memory_kb: 66772
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;

using Int = long long;
const char newl = '\n';

template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
template<typename T> void drop(const T &x){cout<<x<<endl;exit(0);}
template<typename T=int>
vector<T> read(size_t n){
  vector<T> ts(n);
  for(size_t i=0;i<n;i++) cin>>ts[i];
  return ts;
}

template<typename Vertex, typename Cluster, size_t LIM>
struct TopTree{
  enum Type { Compress, Rake, Edge };
  struct Node{
    Vertex* vs[2];
    Cluster dat;
    Node* p;
    Node* q;
    Node* ch[2];
    bool rev,guard;
    Type type;
    Node():p(nullptr),q(nullptr),rev(false),guard(false){}
  };

  static array<Vertex, LIM> pool_v;
  static array<Node, LIM> pool_c;
  size_t ptr_v,ptr_c;

  Cluster id;
  TopTree():ptr_v(0),ptr_c(0),id(){}

  inline Vertex* create(Vertex v=Vertex()){
    auto t=&pool_v[ptr_v++];
    auto dummy=&pool_v[ptr_v++];
    *t=v;
    link(t,id,dummy);
    return t;
  }

  inline Node* edge(Vertex* u,Cluster w,Vertex* v){
    auto t=&(pool_c[ptr_c++]);
    t->vs[0]=u;t->vs[1]=v;t->dat=w;t->type=Type::Edge;
    return pushup(t);
  }

  inline Node* compress(Node* l,Node* r){
    auto t=&(pool_c[ptr_c++]);
    t->ch[0]=l;t->ch[1]=r;t->type=Type::Compress;
    return pushup(t);
  }

  inline Node* rake(Node* l,Node* r){
    auto t=&(pool_c[ptr_c++]);
    t->ch[0]=l;t->ch[1]=r;t->type=Type::Rake;
    return pushup(t);
  }

  int parent_dir(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->guard) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  int parent_dir_ignore_guard(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  inline Node* pushup(Node* const t){
    Node* const l=t->ch[0];
    Node* const r=t->ch[1];

    if(t->type==Type::Compress){
      assert(l->vs[1]==r->vs[0]);
      t->vs[0]=l->vs[0];
      t->vs[1]=r->vs[1];

      Cluster lf=l->dat;
      if(t->q){
        assert(l->vs[1]==t->q->vs[1]);
        lf=Cluster::rake(l->dat,t->q->dat);
      }
      t->dat=Cluster::compress(lf,r->vs[0],r->dat);

      l->vs[1]->handle=t;
    }

    if(t->type==Type::Rake){
      propagate(t);
      assert(l->vs[1]==r->vs[1]);
      t->vs[0]=l->vs[0];
      t->vs[1]=l->vs[1];
      t->dat=Cluster::rake(l->dat,r->dat);
    }else{
      if(!t->p){
        t->vs[0]->handle=t;
        t->vs[1]->handle=t;
      }else if(t->p->type==Type::Compress){
        if(parent_dir(t)==-1)
          t->vs[0]->handle=t;
      }else if(t->p->type==Type::Rake){
        t->vs[0]->handle=t;
      }
    }
    return t;
  }

  inline void toggle(Node* t){
    if(t->type==Type::Edge){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
    }else if(t->type==Type::Compress){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
      t->rev^=true;
    }else if(t->type==Type::Rake){
    }else abort();
  }

  inline void propagate(Node* t){
    if(t->type==Type::Compress){
      if(t->rev){
        assert(t->ch[0] and t->ch[1]);
        swap(t->ch[0],t->ch[1]);
        toggle(t->ch[0]);
        toggle(t->ch[1]);
        t->rev=false;
      }
    }
  }

  void set_toggle(Node* v){
    toggle(v);propagate(v);
  }

  void pushdown(Node* t){
    if(!t) return;
    pushdown(t->p);
    propagate(t);
  }

  void rotate(Node* t,Node* x,size_t dir){
    Node* y=x->p;
    int par=parent_dir_ignore_guard(x);
    propagate(t->ch[dir]);
    x->ch[dir^1]=t->ch[dir];
    t->ch[dir]->p=x;
    t->ch[dir]=x;
    x->p=t;
    t->p=y;
    if(~par) y->ch[par]=t;
    else if(y and y->type==Type::Compress) y->q=t;
    pushup(x);pushup(t);
    if(y and !y->guard) pushup(y);
  }

  void splay(Node* t){
    assert(t->type!=Type::Edge);
    propagate(t);

    while(~parent_dir(t)){
      Node* q=t->p;
      if(q->type!=t->type) break;
      if(~parent_dir(q) and q->p and q->p->type==q->type){
        Node* r=q->p;
        if(r->p) propagate(r->p);
        propagate(r);propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        int rq_dir=parent_dir(q);
        if(rq_dir==qt_dir){
          rotate(q,r,rq_dir^1);
          rotate(t,q,qt_dir^1);
        }else{
          rotate(t,q,qt_dir^1);
          rotate(t,r,rq_dir^1);
        }
      }else{
        if(q->p) propagate(q->p);
        propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        rotate(t,q,qt_dir^1);
      }
    }
  }

  Node* expose(Node* t){
    pushdown(t);
    while(true){
      assert(t->type!=Type::Rake);
      if(t->type==Type::Compress) splay(t);
      Node* n=nullptr;
      {
        Node* p=t->p;
        if(!p) break;
        if(p->type==Type::Rake){
          propagate(p);
          splay(p);
          n=p->p;
        }
        if(p->type==Type::Compress){
          propagate(p);
          if(p->guard and ~parent_dir_ignore_guard(t)) break;
          n=p;
        }
      }
      splay(n);
      int dir=parent_dir_ignore_guard(n);
      if(dir==-1 or n->p->type==Type::Rake) dir=0;

      Node* const c=n->ch[dir];
      if(dir==1){
        set_toggle(c);
        set_toggle(t);
      }
      int n_dir=parent_dir(t);
      if(~n_dir){
        Node* const r=t->p;
        propagate(c);
        propagate(r);
        r->ch[n_dir]=c;
        c->p=r;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(r);pushup(t);pushup(n);
        splay(r);
      }else{
        propagate(c);
        n->q=c;
        c->p=n;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(t);pushup(n);
      }
      if(t->type==Type::Edge) t=n;
    }
    return t;
  }

  Node* expose(Vertex* v){
    return expose((Node*)(v->handle));
  }

  void soft_expose(Vertex* u,Vertex* v){
    pushdown((Node*)u->handle);
    pushdown((Node*)v->handle);
    Node* rt=expose(u);

    if(u->handle==v->handle){
      if(rt->vs[1]==u or rt->vs[0]==v)
        set_toggle(rt);
      return;
    }

    rt->guard=true;
    Node* soft=expose(v);
    rt->guard=false;

    pushup(rt);
    if(parent_dir(soft)==0) set_toggle(rt);
  }

  void bring(Node* rt){
    Node* rk=rt->q;
    if(!rk){
      Node* ll=rt->ch[0];
      ll->p=nullptr;
      pushup(ll);
    }else if(rk->type==Type::Compress or rk->type==Type::Edge){
      propagate(rk);

      Node* nr=rk;
      set_toggle(nr);
      rt->ch[1]=nr;
      nr->p=rt;
      rt->q=nullptr;

      pushup(nr);pushup(rt);
    }else if(rk->type==Type::Rake){
      propagate(rk);
      while(rk->ch[1]->type==Type::Rake){
        propagate(rk->ch[1]);
        rk=rk->ch[1];
      }
      pushdown(rk);

      rt->guard=true;
      splay(rk);
      rt->guard=false;

      Node* ll=rk->ch[0];
      Node* rr=rk->ch[1];
      propagate(ll);
      set_toggle(rr);

      rt->ch[1]=rr;
      rr->p=rt;

      rt->q=ll;
      ll->p=rt;

      pushup(ll);pushup(rr);pushup(rt);
    }
  }

  Node* link(Vertex* u,Cluster w,Vertex* v){
    if(!u->handle and !v->handle) return edge(u,w,v);

    Node* nnu=(Node*)u->handle;
    Node* nnv=(Node*)v->handle;
    Node* ee=edge(u,w,v);
    Node* ll=nullptr;

    if(!nnv) ll=ee;
    else{
      Node* vv=expose(nnv);
      propagate(vv);
      if(vv->vs[1]==v) set_toggle(vv);
      if(vv->vs[0]==v){
        Node* nv=compress(ee,vv);
        ee->p=nv;
        pushup(ee);
        vv->p=nv;
        pushup(vv);pushup(nv);
        ll=nv;
      }else{
        Node* nv=vv;
        Node* ch=nv->ch[0];
        propagate(ch);
        nv->ch[0]=ee;
        ee->p=nv;
        pushup(ee);

        Node* bt=nv->q;
        Node* rk=nullptr;
        if(bt){
          propagate(bt);
          rk=rake(bt,ch);
          bt->p=rk;
          ch->p=rk;
          pushup(bt);pushup(ch);
        }else{
          rk=ch;
        }
        nv->q=rk;
        rk->p=nv;
        pushup(rk);pushup(nv);
        ll=nv;
      }
    }

    if(nnu){
      Node* uu=expose(nnu);
      propagate(uu);
      if(uu->vs[0]==u) set_toggle(uu);
      if(uu->vs[1]==u){
        Node* tp=compress(uu,ll);
        uu->p=tp;
        ll->p=tp;
        pushup(uu);pushup(ll);pushup(tp);
      }else{
        Node* nu=uu;
        Node* ch=nu->ch[1];
        toggle(ch);
        propagate(ch);

        nu->ch[1]=ll;
        ll->p=nu;
        pushup(ll);

        Node* al=nu->q;
        Node* rk=nullptr;
        if(al){
          propagate(al);
          rk=rake(al,ch);
          al->p=rk;
          ch->p=rk;
          pushup(al);pushup(ch);
        }else{
          rk=ch;
        }
        nu->q=rk;
        rk->p=nu;
        pushup(rk);pushup(nu);
      }
    }
    return ee;
  }

  void cut(Vertex* u,Vertex *v){
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    Node* rr=rt->ch[1];
    rr->p=nullptr;
    set_toggle(rr);
    bring(rr);bring(rt);
  }

  Node* path(Vertex* u,Vertex* v){
    assert(u!=v);
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    propagate(rt->ch[1]);
    return rt->ch[1]->ch[0];
  }

  void set_vertex(Vertex* u,Vertex v){
    auto t=expose(u);
    *u=v;
    pushup(t);
  }

  void set_edge(Vertex* u,Vertex* v,const Cluster &w){
    auto t=path(u,v);
    assert(t->type==Type::Edge);
    t->dat=w;
    while(t) pushup(t),t=t->p;
  }

  Cluster get_path(Vertex* u,Vertex* v){
    return path(u,v)->dat;
  }

  Cluster get_subtree(Vertex* v){
    return expose(v)->dat;
  }

  // subtree of v when p is root
  Cluster get_subtree(Vertex* p,Vertex* v){
    Node* t=path(p,v);
    Cluster res=t->p->ch[1]->dat;
    res.toggle();
    Node* rk=t->p->q;
    if(t->p->q){
      assert(rk->vs[1]==t->p->ch[1]->vs[0]);
      res=Cluster::rake(res,rk->dat);
    }
    return res;
  }
};
template<typename Vertex, typename Cluster, size_t LIM>
array<Vertex, LIM> TopTree<Vertex, Cluster, LIM>::pool_v;
template<typename Vertex, typename Cluster, size_t LIM>
array<typename TopTree<Vertex, Cluster, LIM>::Node, LIM>
TopTree<Vertex, Cluster, LIM>::pool_c;



template<typename T,T MOD = 1000000007>
struct Mint{
  static constexpr T mod = MOD;
  T v;
  Mint():v(0){}
  Mint(signed v):v(v){}
  Mint(long long t){v=t%MOD;if(v<0) v+=MOD;}

  Mint pow(long long k){
    Mint res(1),tmp(v);
    while(k){
      if(k&1) res*=tmp;
      tmp*=tmp;
      k>>=1;
    }
    return res;
  }

  static Mint add_identity(){return Mint(0);}
  static Mint mul_identity(){return Mint(1);}

  Mint inv(){return pow(MOD-2);}

  Mint& operator+=(Mint a){v+=a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator-=(Mint a){v+=MOD-a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator*=(Mint a){v=1LL*v*a.v%MOD;return *this;}
  Mint& operator/=(Mint a){return (*this)*=a.inv();}

  Mint operator+(Mint a) const{return Mint(v)+=a;}
  Mint operator-(Mint a) const{return Mint(v)-=a;}
  Mint operator*(Mint a) const{return Mint(v)*=a;}
  Mint operator/(Mint a) const{return Mint(v)/=a;}

  Mint operator-() const{return v?Mint(MOD-v):Mint(v);}

  bool operator==(const Mint a)const{return v==a.v;}
  bool operator!=(const Mint a)const{return v!=a.v;}
  bool operator <(const Mint a)const{return v <a.v;}

  static Mint comb(long long n,int k){
    Mint num(1),dom(1);
    for(int i=0;i<k;i++){
      num*=Mint(n-i);
      dom*=Mint(i+1);
    }
    return num/dom;
  }
};
template<typename T,T MOD> constexpr T Mint<T, MOD>::mod;
template<typename T,T MOD>
ostream& operator<<(ostream &os,Mint<T, MOD> m){os<<m.v;return os;}

using M = Mint<int, 998244353>;

struct Vertex{
  M v;
  void* handle;
  Vertex():v(0),handle(nullptr){}
  Vertex(M v):v(v),handle(nullptr){}
};

struct Cluster{
  M len;
  M sum_v;
  M sum_l,sum_r;
  M rake_v,rake_d;
  Cluster(M len=M(0)):len(len),sum_v(0),sum_l(0),sum_r(0),rake_v(0),rake_d(0){}
  void toggle(){
    swap(sum_l,sum_r);
  }
  static Cluster compress(Cluster x,Vertex *v,Cluster y){
    Cluster nxt(x.len+y.len);
    nxt.sum_v=x.sum_v+x.rake_v+(v->v)+y.sum_v;
    nxt.sum_l=x.sum_l+x.rake_d+y.sum_l+(x.sum_v+(v->v)+x.rake_v)*y.len;
    nxt.sum_r=x.sum_r+x.rake_d+y.sum_r+(y.sum_v+(v->v)+x.rake_v)*x.len;
    return nxt;
  }
  static Cluster rake(Cluster x,Cluster y){
    x.rake_v+=y.sum_v+y.rake_v;
    x.rake_d+=y.sum_l+y.rake_d;
    return x;
  }
};

//INSERT ABOVE HERE
signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  int n;
  cin>>n;

  vector<M> vs(n);
  for(int i=0;i<n;i++) cin>>vs[i].v;

  vector<int> as(n),bs(n);
  vector<M> ws(n);
  for(int i=1;i<n;i++){
    cin>>as[i]>>bs[i]>>ws[i].v;
    as[i]--;bs[i]--;
  }

  const size_t LIM = 1e6;
  TopTree<Vertex, Cluster, LIM> G;

  vector<Vertex*> ptr(n);
  for(int i=0;i<n;i++) ptr[i]=G.create(Vertex(vs[i]));

  for(int i=1;i<n;i++)
    G.link(ptr[as[i]],Cluster(0),ptr[bs[i]]);

  M ans{0};
  for(int i=1;i<n;i++){
    Cluster x=G.get_subtree(ptr[bs[i]],ptr[as[i]]);
    Cluster y=G.get_subtree(ptr[as[i]],ptr[bs[i]]);
    ans+=ws[i]*(x.sum_v+x.rake_v+vs[as[i]])*(y.sum_v+y.rake_v+vs[bs[i]]);
    G.set_edge(ptr[as[i]],ptr[bs[i]],Cluster(ws[i]));
  }
  cout<<ans<<newl;

  Vertex* rt=G.create(Vertex(0));

  int q;
  cin>>q;
  for(int i=0;i<q;i++){
    int t;
    cin>>t;
    if(t==1){
      int c,a;
      cin>>c>>a;
      c--;
      G.link(rt,Cluster(0),ptr[c]);
      Cluster x=G.get_subtree(rt,ptr[c]);
      G.cut(rt,ptr[c]);
      // cout<<x.sum_l<<' '<<x.sum_r<<' '<<x.rake_d<<newl;
      ans+=M(a)*(x.sum_l+x.rake_d);
      vs[c]+=M(a);
      G.set_vertex(ptr[c],Vertex(vs[c]));
    }

    if(t==2){
      int e,a;
      cin>>e>>a;

      Cluster x=G.get_subtree(ptr[bs[e]],ptr[as[e]]);
      Cluster y=G.get_subtree(ptr[as[e]],ptr[bs[e]]);
      ans+=M(a)*(x.sum_v+x.rake_v+vs[as[e]])*(y.sum_v+y.rake_v+vs[bs[e]]);

      ws[e]+=M(a);
      G.set_edge(ptr[as[e]],ptr[bs[e]],Cluster(ws[e]));
    }
    cout<<ans<<newl;
  }
  return 0;
}
accuracy: 1
time_ms: 1400
memory_kb: 104672
final_rank: 11

code_snippet: #include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <cmath>
#include <bitset>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <algorithm>
#include <complex>
#include <unordered_map>
#include <unordered_set>
#include <random>
#include <cassert>
#include <fstream>
#include <utility>
#include <functional>
#include <time.h>
#include <stack>
#include <array>
#include <list>
#define popcount __builtin_popcount
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
template<int MOD>
struct ModInt{
	int x;
	ModInt(): x(0){}
	ModInt(ll y): x(y>=0 ? y%MOD : (MOD-(-y)%MOD)%MOD){}

	ModInt &operator+=(const ModInt &p){
		if((x+=p.x)>=MOD) x-=MOD;
		return *this;
	}
	ModInt &operator-=(const ModInt &p){
		if((x+=MOD-p.x)>=MOD) x-=MOD;
		return *this;
	}
	ModInt &operator*=(const ModInt &p){
		x=(int)(1ll*x*p.x%MOD);
		return *this;
	}
	ModInt &operator/=(const ModInt &p){
		*this*=p.inv();
		return *this;
	}

	ModInt operator-() const{ return ModInt(-x);}
	ModInt operator+(const ModInt &p) const{ return ModInt(*this)+=p;}
	ModInt operator-(const ModInt &p) const{ return ModInt(*this)-=p;}
	ModInt operator*(const ModInt &p) const{ return ModInt(*this)*=p;}
	ModInt operator/(const ModInt &p) const{ return ModInt(*this)/=p;}
	bool operator==(const ModInt &p) const{ return x==p.x;}
	bool operator!=(const ModInt &p) const{ return x!=p.x;}

	ModInt pow(ll n) const{
		ModInt ret(1), p(x);
		while(n){
			if(n&1) ret*=p;
			p*=p;
			n>>=1;
		}
		return ret;
	}
	ModInt inv() const{
		return pow(MOD-2);
	}
};
const int MOD=998244353;
using mint=ModInt<MOD>;
struct LinkCutTree{
	struct Node{
		Node *l, *r, *p;
		bool rev;
		int idx;
		mint val, sz, szl;
		mint cost, sum, suml, costs, sum2;
		Node(mint val, int idx, mint cost):cost(cost), costs(cost), sum(0), sum2(0), suml(0), idx(idx), val(val), sz(val), szl(0), rev(false), l(nullptr), r(nullptr), p(nullptr){}
		bool is_root(){
			return !p || (p->l!=this && p->r!=this);
		}
	};
	vector<Node*> v;
	LinkCutTree(int n){
		v.resize(n);
		for(int i=0; i<n; i++) v[i]=new Node(mint(0), i, mint(0));
	}
	void toggle(Node *t){
		if(!t) return;
		swap(t->sum, t->sum2);
		swap(t->l, t->r);
		t->rev^=true;
	}
	void push(Node *t){
		if(!t) return;
		if(t->rev){
			toggle(t->l);
			toggle(t->r);
			t->rev=false;
		}
	}
	void update(Node *t){
		t->sz=t->val+t->szl, t->costs=t->cost;
		if(t->l) t->sz+=t->l->sz, t->costs+=t->l->costs;
		if(t->r) t->sz+=t->r->sz, t->costs+=t->r->costs;
		t->sum=t->suml+t->cost*t->szl;
		t->sum2=t->suml+t->cost*t->szl;
		if(t->l) t->sum+=t->l->sum, t->sum2+=t->l->sum2, t->sum+=t->l->costs*(t->val+t->szl), t->sum2+=t->l->sz*t->cost;
		if(t->r) t->sum+=t->r->sum, t->sum2+=t->r->sum2, t->sum+=t->r->sz*t->cost, t->sum2+=t->r->costs*(t->val+t->szl);
		if(t->l && t->r) t->sum+=t->l->costs*t->r->sz, t->sum2+=t->r->costs*t->l->sz;
	}
	void rotate(Node *t){
		Node *p=t->p, *pp=p->p, *ch;
		if(p->l==t) ch=t->r;
		else ch=t->l;
		if(pp){
			if(pp->l==p) pp->l=t;
			else if(pp->r==p) pp->r=t;
		}
		t->p=pp;
		if(p->l==t) t->r=p;
		else t->l=p;
		p->p=t;
		if(p->l==t) p->l=ch;
		else p->r=ch;
		if(ch) ch->p=p;
		update(p);
		update(t);
	}
	int state(Node *t){
		if(t->is_root()) return 0;
		else if(t->p->l==t) return 1;
		else return -1;
	}
	void splay(Node *t){
		push(t);
		while(state(t)){
			if(!state(t->p)){
				push(t->p); push(t);
				rotate(t);
			}else{
				push(t->p->p); push(t->p); push(t);
				if(state(t->p)==state(t)){
					rotate(t->p);
					rotate(t);
				}else{
					rotate(t);
					rotate(t);
				}
			}
		}
	}
	Node *expose(Node *t){
		Node *rp=nullptr;
		for(Node *now=t; now; now=now->p){
			splay(now);
			if(rp){
				now->szl-=rp->sz;
				now->suml-=rp->sum;
			}
			if(now->r){
				now->szl+=now->r->sz;
				now->suml+=now->r->sum;
			}
			now->r=rp;
			update(now);
			rp=now;
		}
		splay(t);
		return rp;
	}
	void link(Node *c, Node *p){
		expose(c);
		expose(p);
		p->r=c;
		c->p=p;
		update(p);
	}
	void cut(Node *c){
		expose(c);
		c->l->p=nullptr;
		c->l=nullptr;
		update(c);
	}
	void evert(Node *t){
		expose(t);
		toggle(t);
		push(t);
	}
};
int main()
{
	int n; cin>>n;
	LinkCutTree lct(n);
	using node=LinkCutTree::Node;
	for(int i=0; i<n; i++){
		int v; cin>>v;
		lct.v[i]->val=mint(v);
	}
	int a[200020], b[200020];
    for(int i=0; i<n-1; i++){
        int w;
		cin>>a[i]>>b[i]>>w;
        a[i]--; b[i]--;
        node *e=new node(mint(0), i+n, mint(w));
        lct.v.push_back(e);
		lct.link(e, lct.v[a[i]]);
		lct.evert(e);
		lct.link(e, lct.v[b[i]]);
    }
	mint sum(0), sv(0);
	for(int i=0; i<n; i++){
		sv+=lct.v[i]->val;
		lct.evert(lct.v[i]);
		sum+=lct.v[i]->val*lct.v[i]->sum;
	}
	sum/=mint(2);
	printf("%d\n", sum.x);
	int q; cin>>q;
    while(q--){
        int t, c, x; cin>>t>>c>>x;
		c--;
        if(t==1){
			lct.evert(lct.v[c]);
			sum+=mint(x)*lct.v[c]->sum;
			lct.v[c]->val+=mint(x);
			sv+=mint(x);
        }else{
			lct.evert(lct.v[a[c]]);
			lct.cut(lct.v[c+n]);
			mint sl=lct.v[a[c]]->sz;
			lct.v[c+n]->cost+=mint(x);
			lct.link(lct.v[c+n], lct.v[a[c]]);
            sum+=sl*(sv-sl)*mint(x);
        }
		printf("%d\n", sum.x);
    }
	return 0;
}
accuracy: 1
time_ms: 1140
memory_kb: 39164
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<class T> using vec = vector<T>;
template<class T> using vvec = vec<vec<T>>;

constexpr ll mod = 998244353;
struct mint {
    ll x;
    mint(ll x=0):x((x%mod+mod)%mod){}
    
    friend ostream &operator<<(ostream& os,const mint& a){
        return os << a.x;
    }

    friend istream &operator>>(istream& is,mint& a){
        ll t;
        is >> t;
        a = mint(t);
        return (is);
    }

    mint& operator+=(const mint a) {
        if ((x += a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator-=(const mint a) {
        if ((x += mod-a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator*=(const mint a) {
        (x *= a.x) %= mod;
        return *this;
    }
    mint operator+(const mint a) const {
        mint res(*this);
        return res+=a;
    }
    mint operator-(const mint a) const {
        mint res(*this);
        return res-=a;
    }
    mint operator*(const mint a) const {
        mint res(*this);
        return res*=a;
    }
    mint pow(ll t) const {
        if (!t) return 1;
        mint a = pow(t>>1);
        a *= a;
        if (t&1) a *= *this;
        return a;
    }
    // for prime mod
    mint inv() const {
        return pow(mod-2);
    }
    mint& operator/=(const mint a) {
        return (*this) *= a.inv();
    }
    mint operator/(const mint a) const {
        mint res(*this);
        return res/=a;
    }
    bool operator==(const mint& a)const{
        return x==a.x;
    }
};


template<typename Monoid,typename OperatorMonoid,typename F,typename G,typename H>
class LazySegmentTree {
private:
    int sz,height;
    vec<Monoid> data;
    vec<OperatorMonoid> lazy;
    const F op;
    const G homo;
    const H comp;
    const Monoid e;
    const OperatorMonoid Oe;
public:
    LazySegmentTree(int n,const F op,const G homo,const H comp,
                    const Monoid &e,const OperatorMonoid Oe)
        : op(op),homo(homo),comp(comp),e(e),Oe(Oe) {
        sz = 1;
        height = 0;
        while(sz<=n) sz <<= 1,height++;
        data.assign(2*sz,e);
        lazy.assign(2*sz,Oe);
    }

    void set(int k,const Monoid &x) {
        data[k+sz] = x;
    }

    void build() {
        for(int k=sz-1;k>0;k--) {
            data[k] = op(data[2*k], data[2*k+1]);
        }
    }

    inline void propagate(int k) {
        if(lazy[k]!=Oe) {
            lazy[2*k] = comp(lazy[2*k], lazy[k]);
            lazy[2*k+1] = comp(lazy[2*k+1], lazy[k]);
            data[k] = reflect(k);
            lazy[k] = Oe;
        }
    }

    inline Monoid reflect(int k) {
        return lazy[k] == Oe? data[k]:homo(data[k],lazy[k]);
    }

    inline void recalc(int k) {
        while(k>>=1) data[k] = op(reflect(2*k), reflect(2*k+1));
    }

    inline void thrust(int k) {
        for(int i=height;i>0;i--) propagate(k>>i);
    }

    void update(int a, int b, const OperatorMonoid &x) {
        thrust(a+=sz);
        thrust(b+=sz-1);
        for(int l=a,r=b+1;l<r;l>>=1,r>>=1) {
            if(l&1) lazy[l] = comp(lazy[l],x),++l;
            if(r&1) --r, lazy[r] = comp(lazy[r],x);
        }
        recalc(a);
        recalc(b);
    }

    Monoid query(int a, int b) {
        thrust(a+=sz);
        thrust(b+=sz-1);
        Monoid L = e, R = e;
        for(int l=a, r=b+1;l<r;l>>= 1,r>>=1) {
            if(l&1) L = op(L,reflect(l++));
            if(r&1) R = op(reflect(--r),R);
        }
        return op(L,R);
    }

    Monoid operator[](const int &k) {
        return query(k,k+1);
    }
};

struct edge{
    int to,id;
    ll dist;
    edge(int to,ll dist=1,int id=1):to(to),id(id),dist(dist){};
};

class HeavLightDecomposition{
private:
    vvec<edge> g;
    vec<int> sz,in,out,head,par,depth;
    int pos;

    void dfs_sz(int cur,int p){
        sz[cur] = 1;
        par[cur] = p;
        for(auto& e:g[cur]) if(e.to!=p){
            depth[e.to] = depth[cur]+1;
            dfs_sz(e.to,cur);
            sz[cur] += sz[e.to];
            if(sz[e.to]>sz[g[cur][0].to]) swap(e,g[cur][0]);
        }
    }

    void dfs_hld(int cur,int p){
        in[cur] = pos++;
        for(auto& e:g[cur]) if(e.to!=p){
            head[e.to] = (e.to==g[cur][0].to? head[cur]:e.to);
            dfs_hld(e.to,cur);
        }
        out[cur] = pos;
    }
public:
    HeavLightDecomposition(){}
    HeavLightDecomposition(int N,int root,vvec<edge> tree):
    g(tree),sz(N),in(N),out(N),head(N),par(N),depth(N){
        pos = 0;
        depth[root] = 0;
        dfs_sz(root,-1);
        dfs_hld(root,-1);
    }

    int lca(int u,int v){
        while(true){
            if(in[u]>in[v]) swap(u,v);
            if(head[u]==head[v]) return u;
            v = par[head[v]];
        }
    }

    template<class T,class G>
    void update(int u,int v,const T& x,const G& g, bool isedge=false){
        while(true){
            if(in[u]>in[v]) swap(u,v);
            if(head[u]==head[v]) break;
            g(in[head[v]],in[v]+1,x);
            v = par[head[v]];
        }
        g(in[u]+isedge,in[v]+1,x);
    }


    template<class T,class F,class Q>
    T query(int u,int v,const T &e,const F& f,const Q& q,bool isedge=false){
        T l = e,r = e;
        while(true){
            if(in[u]>in[v]){
                swap(u,v); swap(l,r);
            }
            if(head[u]==head[v]) break;
            l = f(q(in[head[v]],in[v]+1),l);
            v = par[head[v]];
        }
        //非可換演算のときは左を反転！
        //f(rev(f(q(a,b),l),r);
        return f(f(q(in[u]+isedge,in[v]+1),l),r);
    }

    int dep(int n){return depth[n];}
    int get_in(int n){return in[n];}
};

struct state{
    mint e,c,cc,ec,ecc;
    int len;
};

auto op = [](state L,state R)->state{
    mint e = L.e+R.e;
    mint c = L.c+R.c;
    mint cc = L.cc+R.cc;
    mint ec = L.ec+R.ec;
    mint ecc = L.ecc+R.ecc;
    int len = L.len+R.len;
    return {e,c,cc,ec,ecc,len};
};

auto func = [](state S,pair<mint,mint> p)->state{
    mint dc = p.first,de = p.second;
    //update by dc
    S.cc += dc*dc*S.len+S.c*dc*2;
    S.c += dc*S.len;
    S.ecc += S.e*dc*dc+S.ec*dc*2;
    S.ec += S.e*dc;
    // update by de;
    S.e += de*S.len;
    S.ec += S.c*de;
    S.ecc += S.cc*de;
    return S;
};

auto comp = [](pair<mint,mint> p,pair<mint,mint> q)->pair<mint,mint>{
    return {p.first+q.first,p.second+q.second};
};

int main() {
    int N;
    cin >> N;
    mint sum = 0;
    vec<mint> V(N);
    for(auto& x:V){
        cin >> x;
        sum += x;
    }
    vvec<edge> g(N);
    vec<int> A(N-1),B(N-1);
    vec<ll> W(N-1);
    for(int i=0;i<N-1;i++){
        int a,b;
        cin >> a >> b >> W[i];
        a--; b--;
        g[a].emplace_back(b,W[i],i);
        g[b].emplace_back(a,W[i],i);
        A[i] = a,B[i] = b;
    }
    LazySegmentTree<state,pair<mint,mint>,decltype(op),decltype(func),decltype(comp)>
    seg(N,op,func,comp,(state){0,0,0,0,0,0},(pair<mint,mint>){0,0});
    HeavLightDecomposition HLD(N,0,g);
    vec<mint> c(N);
    {
        auto dfs = [&](auto&& self,int cur,int par)->void{
            c[cur] = V[cur];
            for(auto& e:g[cur]) if(e.to!=par){
                self(self,e.to,cur);
                c[cur] += c[e.to];
            }
        };
        dfs(dfs,0,-1);
    }

    auto make_state = [&](mint E,mint C)->state{
        mint e = E;
        mint c = C;
        mint cc = C*C;
        mint ec = E*C;
        mint ecc = E*C*C;
        int len = 1;
        return {e,c,cc,ec,ecc,len};
    };

    for(int i=0;i<N-1;i++){
        if(HLD.dep(A[i])>HLD.dep(B[i])) swap(A[i],B[i]);
        seg.set(HLD.get_in(B[i]),make_state(W[i],c[B[i]]));
    }
    seg.build();
    auto calc = [&]()->mint{
        state S = seg.query(0,N);
        return S.ec*sum-S.ecc;
    };

    auto update = [&](int l,int r,pair<mint,mint> p){
        seg.update(l,r,p);
    };

    int Q;
    cin >> Q;
    cout << calc() << "\n";
    for(int i=0;i<Q;i++){
        int t;
        cin >> t;
        if(t==1){
            int v,x;
            cin >> v >> x;
            v--;
            HLD.update(0,v,(pair<mint,mint>){x,0},update,true);
            sum += x;
        }else if(t==2){
            int v,x;
            cin >> v >> x;
            v--;
            HLD.update(B[v],A[v],(pair<mint,mint>){0,x},update,true);
        }
        cout << calc() << "\n";
    }
}
accuracy: 1
time_ms: 520
memory_kb: 102296
final_rank: 7

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 998244353;
const ll INF = mod * mod;
typedef pair<int, int>P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-12;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m) {
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }

const int max_n = 1 << 18;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
using mP = pair<modint, modint>;

struct BIT {
private:
	vector<modint> node, node2; int n;
public:
	BIT(int n_) {
		n = n_; node.resize(n, 0); node2.resize(n, 0);
	}
	//0-indexed
	void add(int a, int b, modint w) {
		for (int i = a; i < n; i |= i + 1)node[i] += (modint)-a * w;
		for (int i = b; i < n; i |= i + 1)node[i] += (modint)b * w;
		for (int i = a; i < n; i |= i + 1)node2[i] += w;
		for (int i = b; i < n; i |= i + 1)node2[i] += -w;
	}
	modint sum(int a) {
		ll ret = 0;
		for (int i = a - 1; i >= 0; i = (i & (i + 1)) - 1)ret += node[i];
		for (int i = a - 1; i >= 0; i = (i & (i + 1)) - 1)ret += (modint)a * node2[i];
		return ret;
	}
	modint sum(int a, int b) {
		return sum(b) - sum(a);
	}
};


vector<mP> ori;
struct SegT {
private:
	int n; vector<mP> node;
	vector<modint> lazy;
	const mP init_c = { 0,0 };
public:
	SegT(vector<int> v) {
		int sz = v.size();
		n = 1;
		while (n < sz)n <<= 1;
		node.resize(2 * n - 1, init_c);
		lazy.resize(2 * n - 1, 0);
		rep(i, sz) {
			modint e = ori[v[i]].first;
			modint c = ori[v[i]].second;
			node[i + n - 1] = { e * c,e };
		}
		per(i, n - 1) {
			node[i] = f(node[2 * i + 1], node[2 * i + 2]);
		}
	}
	mP f(mP a, mP b) {
		return { a.first + b.first,a.second + b.second };
	}
	void eval(int k, int l, int r) {
		if (lazy[k] == (modint)0)return;
		node[k].first += node[k].second * lazy[k];
		if (r - l > 1) {
			lazy[2 * k + 1] += lazy[k];
			lazy[2 * k + 2] += lazy[k];
		}
		lazy[k] = 0;
	}
	void add(modint x, int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0)r = n;
		eval(k, l, r);
		if (r <= a || b <= l)return;
		if (a <= l && r <= b) {
			lazy[k] += x; eval(k, l, r);
		}
		else {
			add(x, a, b, k * 2 + 1, l, (l + r) / 2);
			add(x, a, b, k * 2 + 2, (l + r) / 2, r);
			node[k] = f(node[k * 2 + 1], node[k * 2 + 2]);
		}
	}
	mP query(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0)r = n;
		eval(k, l, r);
		if (r <= a || b <= l)return init_c;
		if (a <= l && r <= b)return node[k];
		else {
			mP vl = query(a, b, k * 2 + 1, l, (l + r) / 2);
			mP vr = query(a, b, k * 2 + 2, (l + r) / 2, r);
			return f(vl, vr);
		}
	}
	void update(int loc, mP x) {
		int k = 0, l = 0, r = n;
		vector<P> st;
		while (k < n - 1) {
			eval(k, l, r);
			st.push_back({ l,r });
			if (loc < (l + r) / 2) {
				k = 2 * k + 1;
				r = (l + r) / 2;
			}
			else {
				k = 2 * k + 2;
				l = (l + r) / 2;
			}
		}
		eval(k, l, r);
		st.push_back({ l,r });
		modint e = x.first, c = x.second;
		node[k] = { e * c,e };
		while (k > 0) {
			k = (k - 1) / 2;
			st.pop_back();
			l = st.back().first, r = st.back().second;
			eval(2 * k + 1, l, (l + r) / 2);
			eval(2 * k + 2, (l + r) / 2, r);
			node[k] = f(node[2 * k + 1], node[2 * k + 2]);
		}
	}
};


struct edge {
	int to;
};
using edges = vector<edge>;
using Graph = vector<edges>;
struct HLDecomposition {
	struct Chain {
		int depth;
		P parent;//chain number,index
		vector<P> child;//child chain number,parent index
		vector<int> mapfrom;
		SegT stree;

		//Chain() { ; }
		Chain(vector<int> seq) :stree(seq) { ; }
	};
	Graph baseG;
	vector<Chain> chains;
	vector<P> mapto;//raw index->chain number &index
	vector<vector<int>> mapfrom;//chain number & index ->raw index

	HLDecomposition() { ; }
	HLDecomposition(const Graph& g) {
		baseG = g;
		const int n = baseG.size();
		mapto = vector<P>(n, P{ -1,-1 });
		mapfrom.clear();
		vector<int> sz(n, 0);
		int start = 0;
		//assert(start != -1);
		size_check_bfs(start, sz);
		decomposition(start, start, 0, 0, 0, sz);
	}
	int depth(int t) {
		return chains[mapto[t].first].depth;
	}

private:
	void size_check_bfs(int start, vector<int>& sz) {
		const int n = baseG.size();
		queue<P> que;
		que.push({ start,start });
		int cnt = 0; vector<int> ord(n, -1);
		while (!que.empty()) {
			int from, parent;
			tie(from, parent) = que.front(); que.pop();
			ord[cnt++] = from;
			for (edge e : baseG[from]) {
				if (e.to == parent)continue;
				que.push({ e.to,from });
			}
		}
		//assert(cnt == n);
		reverse(all(ord));
		rep(i, n) {
			int from = ord[i];
			sz[from] = 1; for (edge e : baseG[from])sz[from] += sz[e.to];
		}
	}
	int decomposition(int from, int parent, int depth, int pnumber, int pindex, const vector<int>& sz) {
		vector<int> seq;
		bfs(from, parent, seq, sz);
		const int c = chains.size();
		chains.push_back(Chain(seq));
		//chains.push_back(Chain());
		chains[c].depth = depth;
		chains[c].parent = { pnumber,pindex };
		rep(i, seq.size()) {
			mapto[seq[i]] = { c,i };
			chains[c].mapfrom.push_back(seq[i]);
		}
		mapfrom.push_back(chains[c].mapfrom);
		rep(i, seq.size()) {
			for (edge e : baseG[seq[i]]) {
				if (mapto[e.to].first != -1)continue;
				int nc = decomposition(e.to, seq[i], depth + 1, c, i, sz);
				chains[c].child.push_back({ nc,i });
			}
		}
		return c;
	}
	void bfs(int from, int parent, vector<int>& seq, const vector<int>& sz) {
		for (;;) {
			seq.push_back(from);
			int best = -1, next = -1;
			for (edge e : baseG[from]) {
				if (e.to == parent)continue;
				if (best < sz[e.to]) {
					best = sz[e.to]; next = e.to;
				}
			}
			if (next == -1)break;
			parent = from; from = next;
		}
	}
	vector<pair<int, P>> all_edge(int u, int v) {
		vector<pair<int, P>> res;
		if (depth(u) > depth(v))swap(u, v);
		while (depth(v) > depth(u)) {
			res.push_back({ mapto[v].first,{ 0,mapto[v].second + 1 } });
			P par = chains[mapto[v].first].parent;
			v = mapfrom[par.first][par.second];
		}
		while (mapto[v].first != mapto[u].first) {
			res.push_back({ mapto[v].first,{ 0,mapto[v].second + 1 } });
			P par = chains[mapto[v].first].parent;
			v = mapfrom[par.first][par.second];
			res.push_back({ mapto[u].first,{ 0,mapto[u].second + 1 } });
			par = chains[mapto[u].first].parent;
			u = mapfrom[par.first][par.second];
		}
		P p = minmax(mapto[v].second, mapto[u].second);
		res.push_back({ mapto[v].first,{ p.first + 1,p.second + 1 } });
		return res;
	}

public:

	void edge_add(int u, int v, int a) {
		vector<pair<int, P>> es = all_edge(u, v);
		rep(i, es.size()) {
			int id = es[i].first;
			int l = es[i].second.first; int r = es[i].second.second;
			chains[id].stree.add(a, l, r);
		}
	}
	void edge_update(int u, mP a) {
		chains[mapto[u].first].stree.update(mapto[u].second, a);
	}
	modint edge_sum(int u, int v) {
		vector<pair<int, P>> es = all_edge(u, v);
		modint res = 0;
		rep(i, es.size()) {
			int id = es[i].first;
			int l = es[i].second.first; int r = es[i].second.second;
			res += chains[id].stree.query(l, r).first;
		}
		return res;
	}


};

struct edge2 {
	int to; modint cost; int id;
};
vector<vector<edge2>> G;
void solve() {
	int n; cin >> n; G.resize(n); ori.resize(n);
	vector<ll> v(n);
	rep(i, n)cin >> v[i];
	vector<modint> costs(n);
	rep(i, n - 1) {
		int a, b, c; cin >> a >> b >> c; a--; b--;
		G[a].push_back({ b,c,i });
		G[b].push_back({ a,c,i });
	}
	vector<int> trans(n);
	vector<int> ri(n);

	vector<int> edgeloc(n - 1);

	BIT fromcost(n);
	BIT vsum(n);

	Graph g(n);

	modint ans = 0;
	modint al = 0; rep(i, n)al += v[i];
	int tmp = 0;
	function<void(int, int)> dfs = [&](int id, int fr) {
		trans[id] = tmp; tmp++;
		for (edge2 e : G[id])if (e.to != fr) {
			dfs(e.to, id);
			edgeloc[e.id] = trans[e.to];
			costs[trans[e.to]] = e.cost;

			fromcost.add(trans[e.to], ri[trans[e.to]], e.cost);

			g[trans[id]].push_back({ trans[e.to] });
			g[trans[e.to]].push_back({ trans[id] });

			modint tosum = vsum.sum(trans[e.to], ri[trans[e.to]]);
			ori[trans[e.to]] = { e.cost,tosum };
			ans += e.cost * tosum * (al - tosum);
		}
		vsum.add(trans[id], trans[id] + 1, v[id]);
		ri[trans[id]] = tmp;
	};
	dfs(0, -1);

	HLDecomposition hld(g);

	modint fromsum = 0;
	rep(i, n) {
		fromsum += fromcost.sum(trans[i], trans[i] + 1) * (modint)v[i];
	}

	//infolist
	//hld.add:v
	//hld.update:e
	//fromcost:e
	//fromsum:e,v
	//vsum:v
	//al :v
	//costs:e
	cout << ans << "\n";
	int q; cin >> q;
	rep(i, q) {
		int t; cin >> t;
		if (t == 1) {
			int a; modint x; ll in; cin >> a >> in; a--; x = in;
			a = trans[a];

			//update answer
			modint d = fromcost.sum(a, a + 1);
			ans += d * x * al;
			ans += x * fromsum;
			ans -= (modint)2 * x * hld.edge_sum(0, a);

			//update info
			hld.edge_add(0, a, x);
			fromsum += d * x;
			vsum.add(a, a + 1, x);
			al += x;
		}
		else if (t == 2) {
			int a; modint x; ll in; cin >> a >> in; a--; x = in;
			a = edgeloc[a];

			//update answer
			modint b = vsum.sum(a, ri[a]);
			ans += (al - b) * b * x;

			//update info
			costs[a] += x;
			hld.edge_update(a, { costs[a],b });
			fromcost.add(a, ri[a], x);
			fromsum += x * b;
		}
		cout << ans << "\n";
	}
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	//cout << fixed << setprecision(15);
	//init_f();
	//expr();
	//int t; cin >> t; rep(i, t)
	solve();
	return 0;
}
accuracy: 1
time_ms: 320
memory_kb: 124784
final_rank: 8

code_snippet: #include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <numeric>
#include <bitset>
#include <cmath>

static const int MOD = 998244353;
using ll = long long;
using u32 = unsigned;
using u64 = unsigned long long;
using namespace std;

template<class T> constexpr T INF = ::numeric_limits<T>::max()/32*15+208;

template <u32 M>
struct modint {
    u32 val;
public:
    static modint raw(int v) { modint x; x.val = v; return x; }
    modint() : val(0) {}
    template <class T>
    modint(T v) { ll x = (ll)(v%(ll)(M)); if (x < 0) x += M; val = u32(x); }
    modint(bool v) { val = ((unsigned int)(v) % M); }
    modint& operator++() { val++; if (val == M) val = 0; return *this; }
    modint& operator--() { if (val == 0) val = M; val--; return *this; }
    modint operator++(int) { modint result = *this; ++*this; return result; }
    modint operator--(int) { modint result = *this; --*this; return result; }
    modint& operator+=(const modint& b) { val += b.val; if (val >= M) val -= M; return *this; }
    modint& operator-=(const modint& b) { val -= b.val; if (val >= M) val += M; return *this; }
    modint& operator*=(const modint& b) { u64 z = val; z *= b.val; val = (u32)(z % M); return *this; }
    modint& operator/=(const modint& b) { return *this = *this * b.inv(); }
    modint operator+() const { return *this; }
    modint operator-() const { return modint() - *this; }
    modint pow(long long n) const { modint x = *this, r = 1; while (n) { if (n & 1) r *= x; x *= x; n >>= 1; } return r; }
    modint inv() const { return pow(M-2); }
    friend modint operator+(const modint& a, const modint& b) { return modint(a) += b; }
    friend modint operator-(const modint& a, const modint& b) { return modint(a) -= b; }
    friend modint operator*(const modint& a, const modint& b) { return modint(a) *= b; }
    friend modint operator/(const modint& a, const modint& b) { return modint(a) /= b; }
    friend bool operator==(const modint& a, const modint& b) { return a.val == b.val; }
    friend bool operator!=(const modint& a, const modint& b) { return a.val != b.val; }
};
using mint = modint<MOD>;

class HeavyLightDecomposition {
    void dfs_sz(int v){
        for (auto &&u : G[v]) {
            if(u == par[v]) continue;
            par[u] = v; dep[u] = dep[v] + 1;
            dfs_sz(u);
            sub_size[v] += sub_size[u];
            if(sub_size[u] > sub_size[G[v][0]]) swap(u, G[v][0]);
        }
    }

    void dfs_hld(int v, int c, int &pos){
        id[v] = pos++;
        id_inv[id[v]]= v;
        tree_id[v] = c;
        for (auto &&u : G[v]) {
            if(u == par[v]) continue;
            head[u] = (u == G[v][0] ? head[v] : u);
            dfs_hld(u, c, pos);
        }
    }

public:
    int n;
    vector<vector<int>> G;
    vector<int> par, dep, sub_size, id, id_inv, tree_id, head;
    explicit HeavyLightDecomposition(int n) : n(n), G(n), par(n), dep(n), sub_size(n, 1),
                                              id(n), id_inv(n), tree_id(n), head(n){}
    explicit HeavyLightDecomposition(vector<vector<int>> &G) :
            G(G), n(G.size()), par(n), dep(n) , sub_size(n, 1), id(n), id_inv(n), tree_id(n), head(n) {}

    void add_edge(int u, int v){
        G[u].emplace_back(v);
        G[v].emplace_back(u);
    }

    void build(vector<int> roots = {0}){
        int c = 0, pos = 0;
        for (auto &&i : roots) {
            dfs_sz(i);
            head[i] = i;
            dfs_hld(i, c++, pos);
        }
    }

    int lca(int u, int v){
        while(true){
            if(id[u] > id[v]) swap(u, v);
            if(head[u] == head[v]) return u;
            v = par[head[v]];
        }
    }

    int distance(int u, int v){
        return dep[u] + dep[v] - 2*dep[lca(u, v)];
    }


    template<typename F>
    void query(int u, int v, const F &f){
        while(true){
            if(id[u] > id[v]) swap(u, v);
            f(max(id[head[v]], id[u]), id[v]+1);
            if(head[u] == head[v]) break;
            v = par[head[v]];
        }
    }

    template<typename F>
    void query_edge(int u, int v, const F &f){
        while(true){
            if(id[u] > id[v]) swap(u, v);
            if(head[u] != head[v]) {
                f(id[head[v]], id[v]+1);
                v = par[head[v]];
            }else {
                if(u != v) f(id[u]+1, id[v]+1);
                break;
            }
        }
    }

    template<typename T, typename Q, typename F>
    T query(int u, int v, const T &e, const Q &q, const F &f){
        T l = e, r = e;
        while(true){
            if(id[u] > id[v]) swap(u, v), swap(l, r);
            l = f(l, q(max(id[head[v]], id[u]), id[v]+1));
            if(head[u] != head[v]) v = par[head[v]];
            else break;
        }
        return f(l, r);
    }

};

template <class M>
struct LazySegmentTree{
    using T = typename M::T;
    using L = typename M::L;
    int sz, n, height{};
    vector<T> seg; vector<L> lazy;
    explicit LazySegmentTree(int n) : n(n) {
        sz = 1; while(sz < n) sz <<= 1, height++;
        seg.assign(2*sz, M::e());
        lazy.assign(2*sz, M::l());
    }

    void set(int k, const T &x){ seg[k + sz] = x; }

    void build(){
        for (int i = sz-1; i > 0; --i) seg[i] = M::f(seg[i<<1], seg[(i<<1)|1]);
    }

    T reflect(int k){ return lazy[k] == M::l() ? seg[k] : M::g(seg[k], lazy[k]); }

    void eval(int k){
        if(lazy[k] == M::l()) return;
        if(k < sz){
            lazy[(k<<1)|0] = M::h(lazy[(k<<1)|0], lazy[k]);
            lazy[(k<<1)|1] = M::h(lazy[(k<<1)|1], lazy[k]);
        }
        seg[k] = reflect(k);
        lazy[k] = M::l();
    }
    void thrust(int k){ for (int i = height; i; --i) eval(k>>i); }
    void recalc(int k) { while(k >>= 1) seg[k] = M::f(reflect((k<<1)|0), reflect((k<<1)|1));}

    void update(int a, const T &x){
        thrust(a += sz);
        seg[a] = x;
        recalc(a);
    }

    void update(int a, int b, const L &x){
        thrust(a += sz); thrust(b += sz-1);
        for (int l = a, r = b+1;l < r; l >>=1, r >>= 1) {
            if(l&1) lazy[l] = M::h(lazy[l], x), l++;
            if(r&1) --r, lazy[r] = M::h(lazy[r], x);
        }
        recalc(a);
        recalc(b);
    }

    T query(int a, int b){ // [l, r)
        thrust(a += sz);
        thrust(b += sz-1);
        T ll = M::e(), rr = M::e();
        for(int l = a, r = b+1; l < r; l >>=1, r>>=1) {
            if (l & 1) ll = M::f(ll, reflect(l++));
            if (r & 1) rr = M::f(reflect(--r), rr);
        }
        return M::f(ll, rr);
    }

    template<class F>
    int search_right(int l, F cond){
        if(l == n) return n;
        thrust(l += sz);
        T val = M::e();
        do {
            while(!(l&1)) l >>= 1;
            if(!cond(M::f(val, seg[l]))){
                while(l < sz) {
                    eval(l); l <<= 1;
                    if (cond(M::f(val, reflect(l)))){
                        val = M::f(val, reflect(l++));
                    }
                }
                return l - sz;
            }
            val = M::f(val, reflect(l++));
        } while((l & -l) != l);
        return n;
    }

    template<class F>
    int search_left(int r, F cond){
        if(r <= 0) return 0;
        thrust((r += sz)-1);
        T val = M::e();
        do {
            r--;
            while(r > 1 && r&1) r >>= 1;
            if(!cond(M::f(reflect(r), val))){
                while(r < sz) {
                    eval(r);
                    r = ((r << 1)|1);
                    if (cond(M::f(reflect(r), val))){
                        val = M::f(reflect(r--), val);
                    }
                }
                return r + 1 - sz;
            }
            val = M::f(reflect(r), val);
        } while((r & -r) != r);
        return 0;
    }
};

struct Monoid{

    using T = array<mint, 6>; // len, x, y, xy, y^2, xy^2
    using L = array<mint, 2>; // dx, dy;
    static T f(T a, T b) {
        T ret{};
        for (int i = 0; i < 6; ++i) ret[i] = a[i]+b[i];
        return ret;
    }
    static T g(T a, L b) {
        T ret = {
                a[0],
                a[1]+b[0],
                a[2]+b[1],
                a[3] + a[1]*b[1] + a[2]*b[0] + b[0]*b[1]*a[0],
                a[4] + a[2]*b[1]*2 + b[1]*b[1]*a[0],
                a[5] + b[1]*(b[1]*(a[0]*b[0]+a[1])+(b[0]*a[2]+a[3])*2) + b[0]*a[4]
        };
        return ret;
    }
    static L h(L a, L b) {
        return {a[0]+b[0], a[1]+b[1]};
    }
    static T e() { return {}; }
    static L l() { return {}; }
};

int main() {
    int n;
    cin >> n;
    mint s = 0;
    vector<int> v(n);
    for (auto &&i : v) scanf("%d", &i), s += i;
    HeavyLightDecomposition hld(n);
    vector<int> a(n-1), b(n-1), w(n-1);
    vector<vector<pair<int, int>>> G(n);
    for (int i = 0; i < n-1; ++i) {
        cin >> a[i] >> b[i] >> w[i];
        a[i]--; b[i]--;
        hld.add_edge(a[i], b[i]);
        G[a[i]].emplace_back(b[i], i*2);
        G[b[i]].emplace_back(a[i], i*2+1);
    }
    vector<int> to(n-1); // どの頂点に辺を任せるか
    hld.build();
    vector<mint> dp(n);
    for (int i = 0; i < n; ++i) dp[i] = v[i];
    LazySegmentTree<Monoid> seg(n);
    auto dfs = [&](int x, int par, auto &&f) -> void {
        for (auto &&i : G[x]) {
            if(i.first != par){
                to[i.second/2] = i.first;
                f(i.first, x, f);
                dp[x] += dp[i.first];
                seg.set(hld.id[i.first], {1, w[i.second/2], dp[i.first], w[i.second/2]*dp[i.first], dp[i.first]*dp[i.first],w[i.second/2]*dp[i.first]*dp[i.first]});
            }
        }
    };
    dfs(0, -1, dfs);
    seg.build();
    int q;
    cin >> q;
    auto ans = [&](){
        auto res = seg.query(0, n);
        printf("%d\n", (s*res[3]-res[5]).val);
    };
    ans();
    while(q--){
        int t, x, y;
        scanf("%d %d %d", &t, &x, &y);
        x--;
        if(t == 2){
            seg.update(hld.id[to[x]], hld.id[to[x]]+1, {y, 0});
        }else {
            s += y;
            hld.query_edge(0, x, [&](int l, int r){ seg.update(l, r, {0, y}); });
        }
        ans();
    }
    return 0;
}
accuracy: 1
time_ms: 570
memory_kb: 59652
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll=long long;
#define int ll

#define rng(i,a,b) for(int i=int(a);i<int(b);i++)
#define rep(i,b) rng(i,0,b)
#define gnr(i,a,b) for(int i=int(b)-1;i>=int(a);i--)
#define per(i,b) gnr(i,0,b)
#define pb push_back
#define eb emplace_back
#define a first
#define b second
#define bg begin()
#define ed end()
#define all(x) x.bg,x.ed
#define si(x) int(x.size())
#ifdef LOCAL
#define dmp(x) cerr<<__LINE__<<" "<<#x<<" "<<x<<endl
#else
#define dmp(x) void(0)
#endif

template<class t,class u> void chmax(t&a,u b){if(a<b)a=b;}
template<class t,class u> void chmin(t&a,u b){if(b<a)a=b;}

template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;

using pi=pair<int,int>;
using vi=vc<int>;

template<class t,class u>
ostream& operator<<(ostream& os,const pair<t,u>& p){
	return os<<"{"<<p.a<<","<<p.b<<"}";
}

template<class t> ostream& operator<<(ostream& os,const vc<t>& v){
	os<<"{";
	for(auto e:v)os<<e<<",";
	return os<<"}";
}

#define mp make_pair
#define mt make_tuple
#define one(x) memset(x,-1,sizeof(x))
#define zero(x) memset(x,0,sizeof(x))
#ifdef LOCAL
void dmpr(ostream&os){os<<endl;}
template<class T,class... Args>
void dmpr(ostream&os,const T&t,const Args&... args){
	os<<t<<" ";
	dmpr(os,args...);
}
#define dmp2(...) dmpr(cerr,__LINE__,##__VA_ARGS__)
#else
#define dmp2(...) void(0)
#endif

using uint=unsigned;
using ull=unsigned long long;

template<class t,size_t n>
ostream& operator<<(ostream&os,const array<t,n>&a){
	return os<<vc<t>(all(a));
}

template<int i,class T>
void print_tuple(ostream&,const T&){
}

template<int i,class T,class H,class ...Args>
void print_tuple(ostream&os,const T&t){
	if(i)os<<",";
	os<<get<i>(t);
	print_tuple<i+1,T,Args...>(os,t);
}

template<class ...Args>
ostream& operator<<(ostream&os,const tuple<Args...>&t){
	os<<"{";
	print_tuple<0,tuple<Args...>,Args...>(os,t);
	return os<<"}";
}

template<class t>
void print(t x,int suc=1){
	cout<<x;
	if(suc==1)
		cout<<"\n";
	if(suc==2)
		cout<<" ";
}

ll read(){
	ll i;
	cin>>i;
	return i;
}

vi readvi(int n,int off=0){
	vi v(n);
	rep(i,n)v[i]=read()+off;
	return v;
}

pi readpi(int off=0){
	int a,b;cin>>a>>b;
	return pi(a+off,b+off);
}

template<class T>
void print(const vector<T>&v,int suc=1){
	rep(i,v.size())
		print(v[i],i==int(v.size())-1?suc:2);
}

string readString(){
	string s;
	cin>>s;
	return s;
}

template<class T>
T sq(const T& t){
	return t*t;
}

//#define CAPITAL
void yes(bool ex=true){
	#ifdef CAPITAL
	cout<<"YES"<<"\n";
	#else
	cout<<"Yes"<<"\n";
	#endif
	if(ex)exit(0);
	#ifdef LOCAL
	cout.flush();
	#endif
}
void no(bool ex=true){
	#ifdef CAPITAL
	cout<<"NO"<<"\n";
	#else
	cout<<"No"<<"\n";
	#endif
	if(ex)exit(0);
	#ifdef LOCAL
	cout.flush();
	#endif
}
void possible(bool ex=true){
	#ifdef CAPITAL
	cout<<"POSSIBLE"<<"\n";
	#else
	cout<<"Possible"<<"\n";
	#endif
	if(ex)exit(0);
	#ifdef LOCAL
	cout.flush();
	#endif
}
void impossible(bool ex=true){
	#ifdef CAPITAL
	cout<<"IMPOSSIBLE"<<"\n";
	#else
	cout<<"Impossible"<<"\n";
	#endif
	if(ex)exit(0);
	#ifdef LOCAL
	cout.flush();
	#endif
}

constexpr ll ten(int n){
	return n==0?1:ten(n-1)*10;
}

const ll infLL=LLONG_MAX/3;

#ifdef int
const int inf=infLL;
#else
const int inf=INT_MAX/2-100;
#endif

int topbit(signed t){
	return t==0?-1:31-__builtin_clz(t);
}
int topbit(ll t){
	return t==0?-1:63-__builtin_clzll(t);
}
int botbit(signed a){
	return a==0?32:__builtin_ctz(a);
}
int botbit(ll a){
	return a==0?64:__builtin_ctzll(a);
}
int popcount(signed t){
	return __builtin_popcount(t);
}
int popcount(ll t){
	return __builtin_popcountll(t);
}
bool ispow2(int i){
	return i&&(i&-i)==i;
}
ll mask(int i){
	return (ll(1)<<i)-1;
}

bool inc(int a,int b,int c){
	return a<=b&&b<=c;
}

template<class t> void mkuni(vc<t>&v){
	sort(all(v));
	v.erase(unique(all(v)),v.ed);
}

ll rand_int(ll l, ll r) { //[l, r]
	#ifdef LOCAL
	static mt19937_64 gen;
	#else
	static mt19937_64 gen(chrono::steady_clock::now().time_since_epoch().count());
	#endif
	return uniform_int_distribution<ll>(l, r)(gen);
}

template<class t>
void myshuffle(vc<t>&a){
	rep(i,si(a))swap(a[i],a[rand_int(0,i)]);
}

template<class t>
int lwb(const vc<t>&v,const t&a){
	return lower_bound(all(v),a)-v.bg;
}

vvc<int> readGraph(int n,int m){
	vvc<int> g(n);
	rep(i,m){
		int a,b;
		cin>>a>>b;
		//sc.read(a,b);
		a--;b--;
		g[a].pb(b);
		g[b].pb(a);
	}
	return g;
}

vvc<int> readTree(int n){
	return readGraph(n,n-1);
}

struct modinfo{uint mod,root;};
template<modinfo const&ref>
struct modular{
	static constexpr uint const &mod=ref.mod;
	static modular root(){return modular(ref.root);}
	uint v;
	//modular(initializer_list<uint>ls):v(*ls.bg){}
	modular(ll vv=0){s(vv%mod+mod);}
	modular& s(uint vv){
		v=vv<mod?vv:vv-mod;
		return *this;
	}
	modular operator-()const{return modular()-*this;}
	modular& operator+=(const modular&rhs){return s(v+rhs.v);}
	modular&operator-=(const modular&rhs){return s(v+mod-rhs.v);}
	modular&operator*=(const modular&rhs){
		v=ull(v)*rhs.v%mod;
		return *this;
	}
	modular&operator/=(const modular&rhs){return *this*=rhs.inv();}
	modular operator+(const modular&rhs)const{return modular(*this)+=rhs;}
	modular operator-(const modular&rhs)const{return modular(*this)-=rhs;}
	modular operator*(const modular&rhs)const{return modular(*this)*=rhs;}
	modular operator/(const modular&rhs)const{return modular(*this)/=rhs;}
	modular pow(int n)const{
		modular res(1),x(*this);
		while(n){
			if(n&1)res*=x;
			x*=x;
			n>>=1;
		}
		return res;
	}
	modular inv()const{return pow(mod-2);}
	/*modular inv()const{
		int x,y;
		int g=extgcd<ll>(v,mod,x,y);
		assert(g==1);
		if(x<0)x+=mod;
		return modular(x);
	}*/
	friend modular operator+(int x,const modular&y){
		return modular(x)+y;
	}
	friend modular operator-(int x,const modular&y){
		return modular(x)-y;
	}
	friend modular operator*(int x,const modular&y){
		return modular(x)*y;
	}
	friend modular operator/(int x,const modular&y){
		return modular(x)/y;
	}
	friend ostream& operator<<(ostream&os,const modular&m){
		return os<<m.v;
	}
	friend istream& operator>>(istream&is,modular&m){
		ll x;is>>x;
		m=modular(x);
		return is;
	}
	bool operator<(const modular&r)const{return v<r.v;}
	bool operator==(const modular&r)const{return v==r.v;}
	bool operator!=(const modular&r)const{return v!=r.v;}
	explicit operator bool()const{
		return v;
	}
};

extern constexpr modinfo base{998244353,3};
//extern constexpr modinfo base{1000000007,0};
//modinfo base{1,0};
using mint=modular<base>;

//内部でグラフをいじるから in,out を使うときは注意
//VERIFY: yosupo
//CF530F
//CodeChef Persistent Oak
//AOJ GRL5C
template<class E>
struct HLD{
	vvc<E> g;
	int n,rt,cnt;
	vi sub,in,out,par,head,dep;
	vc<E> pare;
	int dfs1(int v,int p,E pe,int d){
		par[v]=p;
		pare[v]=pe;
		dep[v]=d;
		g[v].erase(remove(all(g[v]),p),g[v].ed);
		for(auto&e:g[v]){
			sub[v]+=dfs1(e,v,e,d+1);
			if(sub[g[v][0]]<sub[e])
				swap(g[v][0],e);
		}
		return sub[v];
	}
	void dfs2(int v,int h){
		in[v]=cnt++;
		head[v]=h;
		for(int to:g[v])
			dfs2(to,to==g[v][0]?h:to);
		out[v]=cnt;
	}
	HLD(){}
	HLD(const vvc<E>&gg,int rr):g(gg),n(g.size()),rt(rr),cnt(0),
		sub(n,1),in(n),out(n),par(n,-1),head(n),dep(n),pare(n){
		dfs1(rt,-1,E(),0);
		dfs2(rt,rt);
	}
	int lca(int a,int b){
		while(head[a]!=head[b]){
			if(dep[head[a]]>dep[head[b]])
				swap(a,b);
			b=par[head[b]];
		}
		if(dep[a]>dep[b])
			swap(a,b);
		return a;
	}
	int len(int a,int b){
		return dep[a]+dep[b]-dep[lca(a,b)]*2;
	}
	bool asde(int a,int b){
		return in[a]<=in[b]&&out[b]<=out[a];
	}
	//XX Opencup GP of Korea
	//CF625 F
	//2020 Multi-Uni Contest Day5 G
	//CF415E
	vi index;
	//vs を含む virtual tree を返す
	//返すのは virtual tree に使われた頂点と，辺の集合
	//辺の端点は，virtual tree における番号
	//元の木における番号を virtual tree の頂点番号に写すのが，index という変数
	//辺は ch->par の順
	//virtual tree は行き掛け順で番号がついている
	//特に，頂点 0 が根になるようにできている
	pair<vi,vc<pi>> tree_compress(vi vs){
		if(si(index)==0)index.resize(n);
		assert(index.size());
		auto comp = [&](int x,int y){
			return in[x] < in[y];
		};
		sort(all(vs),comp);
		vs.erase(unique(all(vs)),vs.ed);
		int k = vs.size();
		rep(i,k-1){
			vs.pb(lca(vs[i],vs[i+1]));
		}
		sort(all(vs),comp);
		vs.erase(unique(all(vs)),vs.ed);
		k = vs.size();
		rep(i,k) index[vs[i]] = i;
		vc<pi> es;
		rng(i,1,k){
			int p = lca(vs[i-1],vs[i]);
			es.eb(i,index[p]);
		}
		return mp(vs,es);
	}
};

//merge で片方が inactive のときはもう片方をそのまま返す，
//といったときに，lazy の情報までコピーして渡さないようにする

//get の最後の引数は単位元と口では言いつつ・・・？
//たとえば min で最後の引数を 0 にしても 1 とかが返ってくることはある（一敗）

//VERIFY: yosupo
//KUPC2017I
//HDU 5306 Gorgeous Sequence
//findmin/max CF458E
template<class N>
struct segbeats{
	vc<N> x;
	int s;
	segbeats(){}
	template<class T>
	segbeats(const vc<T>& a){
		int n=a.size();
		s=1;
		while(s<n)s*=2;
		x.resize(s*2);
		rep(i,n)
			x[s+i]=N(a[i]);
		gnr(i,1,s)
			upd(i);
	}
	void push(int i){
		x[i].push(x[i*2],x[i*2+1]);
	}
	void upd(int i){
		x[i]=N::merge(x[i*2],x[i*2+1]);
	}
	template<class F,class... Args>
	void chr(int l,int r,int i,int b,int e,F f,Args&&... args){
		if(e<=l||r<=b)
			return;
		if(b<=l&&r<=e&&(x[i].*f)(forward<Args>(args)...))
			return;
		push(i);
		int m=(l+r)/2;
		chr(l,m,i*2,b,e,f,forward<Args>(args)...);
		chr(m,r,i*2+1,b,e,f,forward<Args>(args)...);
		upd(i);
	}
	template<class F,class... Args>
	void ch(int b,int e,F f,Args&&... args){
		assert(b<=e);
		chr(0,s,1,b,e,f,forward<Args>(args)...);
	}
	//use decltype((declval<N>().*F())()) for old-fashioned judges
	template<class F,class G,class H>
	auto getr(int l,int r,int i,int b,int e,F f,G g,H h){
		if(e<=l||r<=b)
			return h;
		if(b<=l&&r<=e)
			return (x[i].*f)();
		push(i);
		int m=(l+r)/2;
		return g(getr(l,m,i*2,b,e,f,g,h),getr(m,r,i*2+1,b,e,f,g,h));
	}
	template<class F,class G,class H>
	auto get(int b,int e,F f,G g,H h){
		assert(b<=e);
		return getr(0,s,1,b,e,f,g,h);
	}
	auto compositer(int l,int r,int i,int b,int e){
		if(e<=l||r<=b)assert(0);
		if(b<=l&&r<=e)
			return x[i];
		push(i);
		int m=(l+r)/2;
		if(e<=m)return compositer(l,m,i*2,b,e);
		if(m<=b)return compositer(m,r,i*2+1,b,e);
		return N::merge(compositer(l,m,i*2,b,e),compositer(m,r,i*2+1,b,e));
	}
	//work without identity node
	auto composite(int b,int e){
		assert(b<e);
		return compositer(0,s,1,b,e);
	}
	N getall(){return x[1];}
	//return minimum index
	template<class F,class...Args>
	pair<int,N> findminr(int i,int l,int r,int b,int e,F f,Args&&...args){
		if(e<=l||r<=b)return {e,N()};
		if(b<=l&&r<=e){
			if(!(x[i].*f)(forward<Args>(args)...))return {e,N()};
			if(r-l==1)return {l,x[i]};
		}
		push(i);
		int m=(l+r)/2;
		auto a=findminr(i*2,l,m,b,e,f,forward<Args>(args)...);
		if(a.a<e)return a;
		return findminr(i*2+1,m,r,b,e,f,forward<Args>(args)...);
	}
	template<class F,class...Args>
	pair<int,N> findmin(int b,int e,F f,Args&&...args){
		assert(b<=e);
		return findminr(1,0,s,b,e,f,forward<Args>(args)...);
	}
	//return maximum index
	template<class F,class...Args>
	pair<int,N> findmaxr(int i,int l,int r,int b,int e,F f,Args&&...args){
		if(e<=l||r<=b)return {b-1,N()};
		if(b<=l&&r<=e){
			if(!(x[i].*f)(forward<Args>(args)...))return {b-1,N()};
			if(r-l==1)return {l,x[i]};
		}
		push(i);
		int m=(l+r)/2;
		auto a=findmaxr(i*2+1,m,r,b,e,f,forward<Args>(args)...);
		if(a.a>=b)return a;
		return findmaxr(i*2,l,m,b,e,f,forward<Args>(args)...);
	}
	template<class F,class...Args>
	pair<int,N> findmax(int b,int e,F f,Args&&...args){
		assert(b<=e);
		return findmaxr(1,0,s,b,e,f,forward<Args>(args)...);
	}
	void enumerater(int l,int r,int i,int b,int e,vc<N>&dst){
		if(e<=l||r<=b)
			return;
		if(l+1==r){
			dst.pb(x[i]);
			return;
		}
		push(i);
		int m=(l+r)/2;
		enumerater(l,m,i*2,b,e,dst);
		enumerater(m,r,i*2+1,b,e,dst);
	}
	void enumerate(int b,int e,vc<N>&dst){
		assert(b<=e);
		return enumerater(0,s,1,b,e,dst);
	}
	
	//KUPC 2020 G
	template<class F,class...Args>
	void enumerate_by_findr(int l,int r,int i,int b,int e,vc<pair<int,N>>&dst,F f,Args&&...args){
		if(e<=l||r<=b||!(x[i].*f)(forward<Args>(args)...))
			return;
		if(l+1==r){
			dst.eb(l,x[i]);
			return;
		}
		push(i);
		int m=(l+r)/2;
		enumerate_by_findr(l,m,i*2,b,e,dst,f,forward<Args>(args)...);
		enumerate_by_findr(m,r,i*2+1,b,e,dst,f,forward<Args>(args)...);
	}
	template<class F,class...Args>
	void enumerate_by_find(int b,int e,vc<pair<int,N>>&dst,F f,Args&&...args){
		assert(b<=e);
		enumerate_by_findr(0,s,1,b,e,dst,f,forward<Args>(args)...);
	}
	void prepare(int i){
		if(i/=2){
			prepare(i);
			push(i);
		}
	}
	//point_update と lazy を組み合わせたらどうなるかは，わからない・・・
	void point_update(int i,N w){
		i+=s;
		prepare(i);
		x[i]=w;
		while(i/=2)
			upd(i);
	}
};

//N::push
//pushしたあとはclearする
//N::merge

//simple range max
struct N{
	mint w,sum,lz;
	N(mint v=0):w(v),sum(0),lz(0){}
	bool addw(mint v){
		w+=v;
		sum+=lz*v;
		return true;
	}
	bool addlz(mint v){
		sum+=w*v;
		lz+=v;
		return true;
	}
	void push(N&x,N&y){
		x.addlz(lz);
		y.addlz(lz);
		lz=0;
	}
	static N merge(N x,N y){
		N res;
		res.w=x.w+y.w;
		res.sum=x.sum+y.sum;
		return res;
	}
	mint getsum(){
		return sum;
	}
};

template<class t>
struct BIT{
	vc<t> buf;
	int s;
	BIT(int n=0){init(n);}
	void init(int n){buf.assign(s=n,0);}
	void add(int i,t v){
		for(;i<s;i+=(i+1)&(-i-1))
			buf[i]+=v;
	}
	t get(int i){
		t res=0;
		for(;i>=0;i-=(i+1)&(-i-1))
			res+=buf[i];
		return res;
	}
	t sum(int b,int e){
		return get(e-1)-get(b-1);
	}
	int kth(int k){
		int res=0;
		for(int i=topbit(s);i>=0;i--){
			int w=res+(1<<i);
			if(w<=s&&buf[w-1]<=k){
				k-=buf[w-1];
				res=w;
			}
		}
		return res;
	}
	//yukicoder No.1024
	int kth_helper(int k,int i){
		return kth(k+get(i-1));
	}
};

struct E{
	int to,idx;
	operator int()const{return to;}
};

signed main(){
	cin.tie(0);
	ios::sync_with_stdio(0);
	cout<<fixed<<setprecision(20);
	
	int n;cin>>n;
	vc<mint> rwv(n);
	rep(i,n)cin>>rwv[i];
	vc<mint> rwe(n-1);
	vvc<E> t(n);
	rep(i,n-1){
		int a,b;cin>>a>>b;
		a--;b--;
		t[a].pb({b,i});
		t[b].pb({a,i});
		mint c;cin>>c;
		rwe[i]=c;
	}
	BIT<mint> cur(n),dep(n);
	HLD<E> hld(t,0);
	segbeats<N> seg(vc<mint>(n,0));
	mint ans=0,sum=0,tot=0;
	auto add_vert=[&](int i,mint w){
		mint d=dep.get(hld.in[i]);
		mint g=0;
		{
			int x=i;
			while(x!=-1){
				int h=hld.head[x];
				int p=hld.par[h];
				int l=hld.in[h]+(p==-1),r=hld.in[x]+1;
				if(l<r){
					g+=seg.get(l,r,&N::getsum,
					[](mint a,mint b){return a+b;},mint(0));
				}
				x=p;
			}
		}
		mint a=cur.sum(hld.in[i],hld.in[i]+1);
		dmp2(d,a,g,sum,tot);
		ans+=(sum+tot*d-g*2)*w;
		sum+=d*w;
		cur.add(hld.in[i],w);
		tot+=w;
		{
			int x=i;
			while(x!=-1){
				int h=hld.head[x];
				int p=hld.par[h];
				int l=hld.in[h]+(p==-1),r=hld.in[x]+1;
				if(l<r)seg.ch(l,r,&N::addlz,w);
				x=p;
			}
		}
	};
	vi cv(n-1);
	rng(i,1,n)cv[hld.pare[i].idx]=i;
	auto add_edge=[&](int i,mint w){
		int v=cv[i],u=hld.par[v];
		mint sub=cur.sum(hld.in[v],hld.out[v]);
		dmp2(sub,tot,w);
		ans+=sub*(tot-sub)*w;
		dep.add(hld.in[v],w);
		dep.add(hld.out[v],-w);
		seg.ch(hld.in[v],hld.in[v]+1,&N::addw,w);
		sum+=w*sub;
	};
	rep(i,n)add_vert(i,rwv[i]);
	dmp(ans);
	rep(i,n-1)add_edge(i,rwe[i]);
	int q;cin>>q;
	print(ans);
	rep(_,q){
		int tp;cin>>tp;
		int i;cin>>i;i--;
		mint x;cin>>x;
		if(tp==1){
			add_vert(i,x);
		}else{
			add_edge(i,x);
		}
		print(ans);
	}
}
accuracy: 1
time_ms: 850
memory_kb: 69240
final_rank: 6

code_snippet: #include <bits/extc++.h>

struct graph {
  struct edge {
    int src, dst;
    int64_t cost;

    int operator-(int v) const {
      assert(v == src or v == dst);
      return src ^ dst ^ v;
    }
  };

  int n, m;
  std::vector<edge> edges;
  std::vector<std::vector<std::pair<int, int>>> adj;
  std::function<bool(int)> ignore;

  graph(int _n = 0) : n(_n), m(0), adj(n), ignore([](int) { return false; }) {}

  int add(const edge& e, bool directed) {
    assert(0 <= e.src), assert(e.src < n);
    assert(0 <= e.dst), assert(e.dst < n);
    edges.push_back(e);
    adj[e.src].emplace_back(m, e.dst);
    if (not directed) adj[e.dst].emplace_back(m, e.src);
    return m++;
  }
};

struct dfs_forest : graph {
  using cost_t = decltype(edge::cost);

  std::vector<int> root, pv, pe, sz, depth, min_depth, last, order, in, out;
  std::vector<cost_t> dist;
  int trials;

  dfs_forest(int _n = 0) : graph(_n), dist(n), trials(0) {
    for (auto p : {&root, &pv, &pe, &sz, &depth, &min_depth, &last, &in, &out})
      p->assign(n, -1);
  }

  int add(const edge& e) { return graph::add(e, false); }
  void build(int r, bool clear_order = true) {
    assert(0 <= r), assert(r < n);
    root[r] = r, pv[r] = pe[r] = -1, depth[r] = 0, dist[r] = cost_t{};
    if (clear_order) order.clear();
    dfs(r);
    ++trials;
  }
  void build() {
    fill(begin(root), end(root), -1);
    for (int v = 0; v < n; ++v)
      if (root[v] == -1) build(v, v == 0);
  }
  int deeper(int id) const {
    assert(0 <= id), assert(id < m), assert(not ignore(id));
    int u = edges[id].src, v = edges[id].dst;
    return depth[u] < depth[v] ? v : u;
  }
  bool is_tree_edge(int id) const {
    assert(0 <= id), assert(id < m), assert(not ignore(id));
    return id == pe[deeper(id)];
  }
  bool is_ancestor(int u, int v) const {
    assert(0 <= u), assert(u < n);
    assert(0 <= v), assert(v < n);
    return in[u] <= in[v] and out[v] <= out[u];
  }

 private:
  void dfs(int v) {
    sz[v] = 1, min_depth[v] = depth[v], last[v] = trials;
    in[v] = size(order), order.push_back(v);
    for (auto [id, u] : adj[v]) {
      if (ignore(id) or id == pe[v]) continue;
      if (last[u] == trials) {
        min_depth[v] = std::min(min_depth[v], depth[u]);
        continue;
      }
      root[u] = root[v], pv[u] = v, pe[u] = id, depth[u] = depth[v] + 1;
      dist[u] = dist[v] + edges[id].cost;
      dfs(u);
      sz[v] += sz[u], min_depth[v] = std::min(min_depth[v], min_depth[u]);
    }
    out[v] = size(order);
  }
};

struct hld_forest : dfs_forest {
  std::vector<int> head;

  hld_forest(int _n = 0) : dfs_forest(_n), head(n) {}

  void build_hld(int r, bool clear_order = true) {
    assert(0 <= r), assert(r < n);
    build(r, clear_order);
    order.erase(end(order) - sz[r], end(order));
    head[r] = r;
    dfs_hld(r);
  }
  void build_hld() {
    fill(begin(root), end(root), -1);
    for (int v = 0; v < n; ++v)
      if (root[v] == -1) build_hld(v, v == 0);
  }
  int lca(int u, int v) const {
    assert(0 <= u), assert(u < n);
    assert(0 <= v), assert(v < n);
    assert(root[u] == root[v]);
    while (true) {
      if (in[u] > in[v]) std::swap(u, v);
      if (head[u] == head[v]) return u;
      v = pv[head[v]];
    }
  }
  int d(int u, int v) const {
    assert(0 <= u), assert(u < n);
    assert(0 <= v), assert(v < n);
    assert(root[u] == root[v]);
    return depth[u] + depth[v] - 2 * depth[lca(u, v)];
  }
  cost_t distance(int u, int v) const {
    assert(0 <= u), assert(u < n);
    assert(0 <= v), assert(v < n);
    assert(root[u] == root[v]);
    return dist[u] + dist[v] - 2 * dist[lca(u, v)];
  }
  int la(int v, int d) const {
    assert(0 <= v), assert(v < n);
    assert(0 <= d), assert(d <= depth[v]);
    while (depth[head[v]] > d) v = pv[head[v]];
    return order[in[head[v]] + (d - depth[head[v]])];
  }
  int next(int src, int dst) const {
    assert(0 <= src), assert(src < n);
    assert(0 <= dst), assert(dst < n);
    assert(root[src] == root[dst]);
    assert(src != dst);
    if (not is_ancestor(src, dst)) return pv[src];
    return la(dst, depth[src] + 1);
  }
  int next(int src, int dst, int k) const {
    assert(0 <= src), assert(src < n);
    assert(0 <= dst), assert(dst < n);
    assert(root[src] == root[dst]);
    assert(k >= 0);
    int v = lca(src, dst);
    if (k <= depth[src] - depth[v]) return la(src, depth[src] - k);
    k -= depth[src] - depth[v];
    assert(k <= depth[dst] - depth[v]);
    return la(dst, depth[v] + k);
  }
  template <class Function>
  void apply(int src, int dst, bool vertex, Function func) const {
    assert(0 <= src), assert(src < n);
    assert(0 <= dst), assert(dst < n);
    assert(root[src] == root[dst]);
    int v = lca(src, dst);
    for (auto [a, b] : ascend(src, v)) func(a + 1, b);
    if (vertex) func(in[v], in[v] + 1);
    for (auto [a, b] : descend(v, dst)) func(a, b + 1);
  }

 private:
  void dfs_hld(int v) {
    in[v] = size(order), order.push_back(v);
    sort(begin(adj[v]), end(adj[v]), [&](auto a, auto b) {
      int au = a.second, bu = b.second;
      return (a.first == pe[au]) * sz[au] > (b.first == pe[bu]) * sz[bu];
    });
    for (auto [id, u] : adj[v]) {
      if (ignore(id) or id == pe[v] or not is_tree_edge(id)) continue;
      head[u] = u == adj[v][0].second ? head[v] : u;
      dfs_hld(u);
    }
    out[v] = size(order);
  }
  auto ascend(int src, int dst) const {
    std::vector<std::pair<int, int>> res;
    while (head[src] != head[dst]) {
      res.emplace_back(in[src], in[head[src]]);
      src = pv[head[src]];
    }
    if (src != dst) res.emplace_back(in[src], in[dst] + 1);
    return res;
  }
  std::vector<std::pair<int, int>> descend(int src, int dst) const {
    if (src == dst) return {};
    if (head[src] == head[dst]) return {{in[src] + 1, in[dst]}};
    auto res = descend(src, pv[head[dst]]);
    res.emplace_back(in[head[dst]], in[dst]);
    return res;
  }
};

template <uint32_t Modulus>
struct modular {
  static_assert(int(Modulus) > 0, "Modulus must be in the range [1, 2^31)");
  static constexpr int modulus() { return Modulus; }

  modular() : v(0) {}
  modular(int64_t x) : v(x % Modulus) {
    if (int(v) < 0) v += Modulus;
  }

  explicit operator int() const { return v; }
  modular& operator++() { return ++v == Modulus ? v = 0 : 0, *this; }
  modular& operator--() { return --(v ? v : v = Modulus), *this; }
  modular operator+() const { return *this; }
  modular operator-() const {
    modular res;
    res.v = v ? Modulus - v : 0;
    return res;
  }
  modular& operator*=(modular b) {
    v = uint64_t(v) * b.v % Modulus;
    return *this;
  }
  modular& operator/=(modular b) {
    auto [x, gcd] = extgcd(b.v, Modulus);
    assert(gcd == 1);
    return *this *= x;
  }
  modular& operator+=(modular b) {
    v += b.v - Modulus;
    if (int(v) < 0) v += Modulus;
    return *this;
  }
  modular& operator-=(modular b) {
    v -= b.v;
    if (int(v) < 0) v += Modulus;
    return *this;
  }

  friend modular operator++(modular& a, int) {
    return std::exchange(a, ++modular(a));
  }
  friend modular operator--(modular& a, int) {
    return std::exchange(a, --modular(a));
  }
  friend modular operator*(modular a, modular b) { return a *= b; }
  friend modular operator/(modular a, modular b) { return a /= b; }
  friend modular operator+(modular a, modular b) { return a += b; }
  friend modular operator-(modular a, modular b) { return a -= b; }
  friend std::istream& operator>>(std::istream& is, modular& b) {
    int64_t x;
    return is >> x, b = x, is;
  }
  friend std::ostream& operator<<(std::ostream& os, modular b) {
    return os << b.v;
  }
  friend bool operator==(modular a, modular b) { return a.v == b.v; }
  friend bool operator!=(modular a, modular b) { return a.v != b.v; }

 private:
  static std::pair<int, int> extgcd(int a, int b) {
    std::array x{1, 0};
    while (b) {
      int q = a / b;
      std::swap(x[0] -= q * x[1], x[1]);
      std::swap(a -= q * b, b);
    }
    return {x[0], a};
  }

  uint32_t v;
};

template <class T>
struct fenwick {
  fenwick() {}
  template <class Generator>
  fenwick(int n, Generator gen) : tree(n) {
    for (int i = 0; i < n; ++i) tree[i] = gen(i);
    for (int i = 0; i < n; ++i)
      if (int j = i | (i + 1); j < n) tree[j] += tree[i];
  }

  int size() const { return std::size(tree); }
  void add(int i, T a) {
    assert(0 <= i), assert(i < size());
    for (; i < size(); i |= i + 1) tree[i] += a;
  }
  T sum(int i) const {
    assert(0 <= i), assert(i <= size());
    T res{};
    for (; i; i &= i - 1) res += tree[i - 1];
    return res;
  }
  T sum(int l, int r) const {
    assert(0 <= l), assert(l <= r), assert(r <= size());
    return sum(r) - sum(l);
  }
  T get(int i) const {
    assert(0 <= i), assert(i < size());
    return sum(i, i + 1);
  }

 private:
  std::vector<T> tree;
};

struct segment_tree_base {
  virtual int size() const = 0;

 protected:
  template <class F>
  void forward(int l, int r, F f) const {
    int h = h1(l += size() - 1, r += size());
    for (int s = 0; s < h; ++s)
      if (int i = l >> s; ~i & 1) f(i + 1);
    for (int s = h; s--;)
      if (int i = r >> s; i & 1) f(i - 1);
  }
  template <class F>
  void forward(int l, int r, F f) {
    const_cast<const segment_tree_base*>(this)->forward(l, r, f);
  }
  template <class F>
  void backward(int l, int r, F f) const {
    int h = h1(l += size() - 1, r += size());
    for (int s = 0; s < h; ++s)
      if (int i = r >> s; i & 1) f(i - 1);
    for (int s = h; s--;)
      if (int i = l >> s; ~i & 1) f(i + 1);
  }
  template <class F>
  void backward(int l, int r, F f) {
    const_cast<const segment_tree_base*>(this)->backward(l, r, f);
  }
  template <class F>
  void downward(int l, int r, F f) const {
    if (l == r or (l == 0 and r == size())) return;
    int h = h2(l += size(), r += size());
    for (int s = std::__lg(l); s > h; --s) f(l >> s);
    for (int s = h; s > __builtin_ctz(l); --s) f(l >> s);
    for (int s = h; s > __builtin_ctz(r); --s) f(r >> s);
  }
  template <class F>
  void downward(int l, int r, F f) {
    const_cast<const segment_tree_base*>(this)->downward(l, r, f);
  }
  template <class F>
  void upward(int l, int r, F f) const {
    if (l == r or (l == 0 and r == size())) return;
    int h = h2(l += size(), r += size());
    for (int s = __builtin_ctz(r); s++ < h;) f(r >> s);
    for (int s = __builtin_ctz(l); s++ < h;) f(l >> s);
    for (int s = h; s++ < std::__lg(l);) f(l >> s);
  }
  template <class F>
  void upward(int l, int r, F f) {
    const_cast<const segment_tree_base*>(this)->upward(l, r, f);
  }

 private:
  static int h1(int l, int r) {
    for (int h = 0;; ++h)
      if ((r >> h) - (l >> h) == 1) return h;
  }
  static int h2(int l, int r) {
    l <<= std::__lg(l) < std::__lg(r);
    return std::__lg(l ^ r);
  }
};

template <class T, class Action>
struct lazy_segment_tree : segment_tree_base {
  lazy_segment_tree() {}
  template <class Generator>
  lazy_segment_tree(int n, Generator gen) : tree(2 * n), lazy(n) {
    for (int i = 0; i < n; ++i) tree[n + i] = gen(i);
    for (int i = n; i-- > 1;) pull(i);
  }

  int size() const override { return std::size(lazy); }
  T fold(int l, int r) {
    assert(0 <= l), assert(l <= r), assert(r <= size());
    downward(l, r, [&](int i) { push(i); });
    T res{};
    forward(l, r, [&](int i) { res = res * tree[i]; });
    return res;
  }
  T get(int i) {
    assert(0 <= i), assert(i < size());
    return fold(i, i + 1);
  }
  T fold_all_rotated() const { return size() ? tree[1] : T{}; }
  template <class Function>
  void update(int i, Function func) {
    assert(0 <= i), assert(i < size());
    downward(i, i + 1, [&](int j) { push(j); });
    tree[size() + i] = func(tree[size() + i]);
    upward(i, i + 1, [&](int j) { pull(j); });
  }
  void act(int l, int r, const Action& f) {
    assert(0 <= l), assert(l <= r), assert(r <= size());
    downward(l, r, [&](int i) { push(i); });
    forward(l, r, [&](int i) { apply(i, f); });
    upward(l, r, [&](int i) { pull(i); });
  }
  template <class Predicate>
  int forward_search(int l, int r, Predicate pred) {
    assert(0 <= l), assert(l <= r), assert(r <= size());
    downward(l, r, [&](int i) { push(i); });
    T a{};
    assert(pred(a));
    int res = r;
    forward(l, r, [&](int i) {
      if (res < r) return;
      if (T na = a * tree[i]; pred(na)) {
        a = na;
        return;
      }
      while (i < size()) {
        push(i);
        if (T na = a * tree[i *= 2]; pred(na)) a = na, ++i;
      }
      res = i - size();
    });
    return res;
  }
  template <class Predicate>
  int backward_search(int l, int r, Predicate pred) {
    assert(0 <= l), assert(l <= r), assert(r <= size());
    downward(l, r, [&](int i) { push(i); });
    T a{};
    assert(pred(a));
    int res = l - 1;
    backward(l, r, [&](int i) {
      if (res >= l) return;
      if (T na = a * tree[i]; pred(na)) {
        a = na;
        return;
      }
      while (i < size()) {
        push(i);
        if (T na = a * tree[i = 2 * i + 1]; pred(na)) a = na, --i;
      }
      res = i - size();
    });
    return res;
  }

 private:
  std::vector<T> tree;
  std::vector<Action> lazy;

  void apply(int i, const Action& f) {
    tree[i] = f(tree[i]);
    if (i < size()) lazy[i] = lazy[i] * f;
  }
  void push(int i) {
    apply(2 * i, lazy[i]), apply(2 * i + 1, lazy[i]);
    lazy[i] = Action{};
  }
  void pull(int i) { tree[i] = tree[2 * i] * tree[2 * i + 1]; }
};

using mint = modular<998244353>;

struct node {
  mint sum, coeff;
  friend node operator*(const node& a, const node& b) {
    return {a.sum + b.sum, a.coeff + b.coeff};
  }
};
struct action {
  mint v;
  node operator()(node x) const {
    x.sum += x.coeff * v;
    return x;
  }
  friend action operator*(const action& f, const action& g) {
    return {f.v + g.v};
  }
};

int main() {
  using namespace std;
  cin.tie(nullptr)->sync_with_stdio(false);
  int n;
  cin >> n;
  vector<int> initial_v(n);
  for (auto&& e : initial_v) cin >> e;
  hld_forest g(n);
  for (int _ = n - 1; _--;) {
    int u, v, w;
    cin >> u >> v >> w;
    --u, --v;
    g.add({u, v, w});
  }
  g.build_hld();

  fenwick<mint> fv(n, [&](int i) -> mint { return initial_v[g.order[i]]; });
  fenwick<mint> fe(
      n, [&](int i) -> mint { return i ? g.edges[g.pe[g.order[i]]].cost : 0; });
  lazy_segment_tree<node, action> seg(n, [&](int i) -> node {
    if (i == 0) return {};
    int v = g.order[i];
    int temp = g.edges[g.pe[v]].cost;
    return {fv.sum(g.in[v], g.out[v]) * temp, temp};
  });

  mint ans;
  for (int id = 0; id < n - 1; ++id) {
    int v = g.deeper(id);
    auto temp = fv.sum(g.in[v], g.out[v]);
    ans += g.edges[id].cost * temp * (fv.sum(n) - temp);
  }
  cout << ans << '\n';

  int q;
  cin >> q;
  while (q--) {
    int type;
    cin >> type;
    if (type == 1) {
      int v, x;
      cin >> v >> x;
      --v;
      ans += seg.fold_all_rotated().sum * x;
      mint path;
      g.apply(0, v, false, [&](int l, int r) {
        if (l > r) swap(l, r);
        ans -= seg.fold(l, r).sum * x * 2;
        path += fe.sum(l, r);
      });
      ans += fv.sum(n) * path * x;
      fv.add(g.in[v], x);
      g.apply(0, v, false, [&](int l, int r) {
        if (l > r) swap(l, r);
        seg.act(l, r, {x});
      });
    } else if (type == 2) {
      int id, x;
      cin >> id >> x;
      --id;
      int v = g.deeper(id);
      auto temp = fv.sum(g.in[v], g.out[v]);
      ans += x * temp * (fv.sum(n) - temp);
      fe.add(g.in[v], x);
      seg.update(g.in[v], [&](node e) -> node {
        e.sum += temp * x;
        e.coeff += x;
        return e;
      });
    } else
      assert(false);
    cout << ans << '\n';
  }
}
accuracy: 1
time_ms: 220
memory_kb: 52340
final_rank: 1

code_snippet: #include<bits/stdc++.h>

using namespace std;

using int64 = long long;
// const int mod = 1e9 + 7;
const int mod = 998244353;

const int64 infll = (1LL << 62) - 1;
const int inf = (1 << 30) - 1;

struct IoSetup {
  IoSetup() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    cerr << fixed << setprecision(10);
  }
} iosetup;


template< typename T1, typename T2 >
ostream &operator<<(ostream &os, const pair< T1, T2 > &p) {
  os << p.first << " " << p.second;
  return os;
}

template< typename T1, typename T2 >
istream &operator>>(istream &is, pair< T1, T2 > &p) {
  is >> p.first >> p.second;
  return is;
}

template< typename T >
ostream &operator<<(ostream &os, const vector< T > &v) {
  for(int i = 0; i < (int) v.size(); i++) {
    os << v[i] << (i + 1 != v.size() ? " " : "");
  }
  return os;
}

template< typename T >
istream &operator>>(istream &is, vector< T > &v) {
  for(T &in : v) is >> in;
  return is;
}

template< typename T1, typename T2 >
inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }

template< typename T1, typename T2 >
inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }

template< typename T = int64 >
vector< T > make_v(size_t a) {
  return vector< T >(a);
}

template< typename T, typename... Ts >
auto make_v(size_t a, Ts... ts) {
  return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...));
}

template< typename T, typename V >
typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) {
  t = v;
}

template< typename T, typename V >
typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) {
  for(auto &e : t) fill_v(e, v);
}

template< typename F >
struct FixPoint : F {
  FixPoint(F &&f) : F(forward< F >(f)) {}

  template< typename... Args >
  decltype(auto) operator()(Args &&... args) const {
    return F::operator()(*this, forward< Args >(args)...);
  }
};

template< typename F >
inline decltype(auto) MFP(F &&f) {
  return FixPoint< F >{forward< F >(f)};
}

template< typename SUM, typename KEY >
struct LinkCutTreeSubtree {

  struct Node {
    Node *l, *r, *p;

    KEY key;
    SUM sum;

    bool rev;
    int sz;

    bool is_root() const {
      return !p || (p->l != this && p->r != this);
    }

    Node(const KEY &key, const SUM &sum) :
        key(key), sum(sum), rev(false), sz(1),
        l(nullptr), r(nullptr), p(nullptr) {}
  };

  const SUM ident;

  LinkCutTreeSubtree(const SUM &ident) : ident(ident) {}

  Node *make_node(const KEY &key) {
    auto ret = new Node(key, ident);
    update(ret);
    return ret;
  }

  Node *set_key(Node *t, const KEY &key) {
    expose(t);
    t->key = key;
    update(t);
    return t;
  }

  void toggle(Node *t) {
    swap(t->l, t->r);
    t->sum.toggle();
    t->rev ^= true;
  }

  void push(Node *t) {
    if(t->rev) {
      if(t->l) toggle(t->l);
      if(t->r) toggle(t->r);
      t->rev = false;
    }
  }


  void update(Node *t) {
    t->sz = 1;
    if(t->l) t->sz += t->l->sz;
    if(t->r) t->sz += t->r->sz;
    t->sum.merge(t->key, t->l ? t->l->sum : ident, t->r ? t->r->sum : ident);
  }

  void rotr(Node *t) {
    auto *x = t->p, *y = x->p;
    if((x->l = t->r)) t->r->p = x;
    t->r = x, x->p = t;
    update(x), update(t);
    if((t->p = y)) {
      if(y->l == x) y->l = t;
      if(y->r == x) y->r = t;
      update(y);
    }
  }

  void rotl(Node *t) {
    auto *x = t->p, *y = x->p;
    if((x->r = t->l)) t->l->p = x;
    t->l = x, x->p = t;
    update(x), update(t);
    if((t->p = y)) {
      if(y->l == x) y->l = t;
      if(y->r == x) y->r = t;
      update(y);
    }
  }


  void splay(Node *t) {
    push(t);
    while(!t->is_root()) {
      auto *q = t->p;
      if(q->is_root()) {
        push(q), push(t);
        if(q->l == t) rotr(t);
        else rotl(t);
      } else {
        auto *r = q->p;
        push(r), push(q), push(t);
        if(r->l == q) {
          if(q->l == t) rotr(q), rotr(t);
          else rotl(t), rotr(t);
        } else {
          if(q->r == t) rotl(q), rotl(t);
          else rotr(t), rotl(t);
        }
      }
    }
  }


  Node *expose(Node *t) {
    Node *rp = nullptr;
    for(auto *cur = t; cur; cur = cur->p) {
      splay(cur);
      if(cur->r) cur->sum.add(cur->r->sum);
      cur->r = rp;
      if(cur->r) cur->sum.erase(cur->r->sum);
      update(cur);
      rp = cur;
    }
    splay(t);
    return rp;
  }

  void link(Node *child, Node *parent) {
    expose(child);
    expose(parent);
    child->p = parent;
    parent->r = child;
  }

  void cut(Node *child) {
    expose(child);
    auto *parent = child->l;
    child->l = nullptr;
    parent->p = nullptr;
    update(child);
  }

  void evert(Node *t) {
    expose(t);
    toggle(t);
    push(t);
  }

  Node *lca(Node *u, Node *v) {
    if(get_root(u) != get_root(v)) return nullptr;
    expose(u);
    return expose(v);
  }


  Node *get_kth(Node *x, int k) {
    expose(x);
    while(x) {
      push(x);
      if(x->r && x->r->sz > k) {
        x = x->r;
      } else {
        if(x->r) k -= x->r->sz;
        if(k == 0) return x;
        k -= 1;
        x = x->l;
      }
    }
    return nullptr;
  }

  Node *get_root(Node *x) {
    expose(x);
    while(x->l) {
      push(x);
      x = x->l;
    }
    return x;
  }
};

template< int mod >
struct ModInt {
  int x;

  ModInt() : x(0) {}

  ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}

  ModInt &operator+=(const ModInt &p) {
    if((x += p.x) >= mod) x -= mod;
    return *this;
  }

  ModInt &operator-=(const ModInt &p) {
    if((x += mod - p.x) >= mod) x -= mod;
    return *this;
  }

  ModInt &operator*=(const ModInt &p) {
    x = (int) (1LL * x * p.x % mod);
    return *this;
  }

  ModInt &operator/=(const ModInt &p) {
    *this *= p.inverse();
    return *this;
  }

  ModInt operator-() const { return ModInt(-x); }

  ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }

  ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }

  ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }

  ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }

  bool operator==(const ModInt &p) const { return x == p.x; }

  bool operator!=(const ModInt &p) const { return x != p.x; }

  ModInt inverse() const {
    int a = x, b = mod, u = 1, v = 0, t;
    while(b > 0) {
      t = a / b;
      swap(a -= t * b, b);
      swap(u -= t * v, v);
    }
    return ModInt(u);
  }

  ModInt pow(int64_t n) const {
    ModInt ret(1), mul(x);
    while(n > 0) {
      if(n & 1) ret *= mul;
      mul *= mul;
      n >>= 1;
    }
    return ret;
  }

  friend ostream &operator<<(ostream &os, const ModInt &p) {
    return os << p.x;
  }

  friend istream &operator>>(istream &is, ModInt &a) {
    int64_t t;
    is >> t;
    a = ModInt< mod >(t);
    return (is);
  }

  static int get_mod() { return mod; }
};

using modint = ModInt< mod >;


int main() {


  struct Sum {
    modint all, pdist, cdist, sz, mdist, msz;
    modint v_sum, m_sum;

    Sum() : all(0), pdist(0), cdist(0), sz(0), mdist(0), msz(0), v_sum(0), m_sum(0) {}

    void toggle() {
      swap(pdist, cdist);
    }

    void merge(int64 key, const Sum &parent, const Sum &child) {
      int64 sw = 0;
      v_sum = parent.v_sum + child.v_sum + m_sum;
      if(key < 0) {
        sw = -key;
        v_sum += sw;
        key = 0;
      }
      all = parent.all + key + child.all;
      pdist = parent.pdist + (child.all + key) * (parent.sz + sw + msz) + child.pdist + mdist;
      cdist = child.cdist + (parent.all + key) * (child.sz + sw + msz) + parent.cdist + mdist;
      sz = parent.sz + child.sz + msz + sw;
    }

    void add(const Sum &chsum) {
      mdist += chsum.cdist;
      msz += chsum.sz;
      m_sum += chsum.v_sum;
    }

    void erase(const Sum &chsum) {
      mdist -= chsum.cdist;
      msz -= chsum.sz;
      m_sum -= chsum.v_sum;
    }
  } e;
  int N;
  cin >> N;
  vector< int64 > V(N);
  cin >> V;
  using LCT = LinkCutTreeSubtree< Sum, int64 >;
  LCT lct(e);
  vector< LCT::Node * > vs(N), es(N);
  for(int i = 0; i < N; i++) {
    vs[i] = lct.make_node(-V[i]);
  }
  vector< int > S(N), T(N);
  for(int i = 0; i + 1 < N; i++) {
    int a, b, w;
    cin >> a >> b >> w;
    --a, --b;
    lct.evert(vs[a]);
    lct.evert(vs[b]);
    es[i] = lct.make_node(w);
    lct.link(vs[a], es[i]);
    lct.link(vs[b], es[i]);
    S[i] = a;
    T[i] = b;
  }
  modint all = 0;
  // v[i]を増やすとv[i]からの全点間なんとかを求めれば良い
  for(int i = 0; i < N; i++) {
    lct.evert(vs[i]);
    all += vs[i]->sum.cdist * V[i];
  }
  all /= 2;
  cout << all << "\n";
  int Q;
  cin >> Q;
  while(Q--) {
    int t, a, b;
    cin >> t >> a >> b;
    --a;
    if(t == 1) {
      lct.evert(vs[a]);
      all -= vs[a]->sum.cdist * -vs[a]->key;
      vs[a]->key -= b;
      lct.update(vs[a]);
      all += vs[a]->sum.cdist * -vs[a]->key;
    } else {
      lct.evert(es[a]);
      lct.cut(vs[S[a]]);
      lct.cut(vs[T[a]]);
      modint latte = vs[S[a]]->sum.v_sum;
      modint malta = vs[T[a]]->sum.v_sum;
      all += latte * malta * b;
      es[a]->key += b;
      lct.link(vs[S[a]], es[a]);
      lct.link(vs[T[a]], es[a]);
    }
    cout << all << "\n";
  }
}
accuracy: 1
time_ms: 840
memory_kb: 40580
final_rank: 4

code_snippet: #include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<iomanip>
#include<math.h>
#include<complex>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#include<bitset>
using namespace std;
#define REP(i,m,n) for(int i=(int)m ; i < (int) n ; ++i )
#define rep(i,n) REP(i,0,n)
typedef long long ll;
typedef pair<int,int> pint;
typedef pair<ll,int> pli;
const int inf=1e9+7;
const ll longinf=1LL<<60 ;
const ll mod=998244353 ;
int dx[4]={1,0,-1,0} , dy[4]={0,1,0,-1} ;

struct Node {
    ll abc,ab,ac,bc,a,b,c;
    Node(ll a,ll b, ll c):a(a),b(b),c(c) {
        ab = a * b % mod;
        ac = a * c % mod;
        bc = b * c % mod;
        abc = ab * c % mod;
    }
};

struct Op {
    ll a, b, c;
};

template<typename T, typename S>
struct LazySegmentTree{
    int n;
    vector<T> node;
    vector<S> lazy;
    T E0;
    S E1;

    inline void updatef(S& lazy,S& value){
        //lazy += value;
        lazy.a += value.a;
        if(lazy.a >= mod) lazy.a -= mod;
        lazy.b += value.b;
        if(lazy.b >= mod) lazy.b -= mod;
        lazy.c += value.c;
        if(lazy.c >= mod) lazy.c -= mod;
        //lazy = max(lazy, value);
        //lazy = min(lazy, value);
    }
    inline void calculatef(T& node,S& lazy,int len){
        //node += lazy * len; //区間sumはこっち
        // node += lazy ; //区間maxとか
        if(lazy.a) {
            node.abc = (node.abc + node.bc * lazy.a) % mod;
            node.ab = (node.ab + node.b * lazy.a) % mod;
            node.ac = (node.ac + node.c * lazy.a) % mod;
            node.a += lazy.a;
            if(node.a >= mod)node.a -= mod;
        }
        if(lazy.b) {
            node.abc = (node.abc + node.ac * lazy.b) % mod;
            node.bc = (node.bc + node.c * lazy.b) % mod;
            node.ab = (node.ab + node.a * lazy.b) % mod;
            node.b += lazy.b;
            if(node.b >= mod)node.b -= mod;
        }
        if(lazy.c) {
            node.abc = (node.abc + node.ab * lazy.c) % mod;
            node.ac = (node.ac + node.a * lazy.c) % mod;
            node.bc = (node.bc + node.b * lazy.c) % mod;
            node.c += lazy.c;
            if(node.c >= mod)node.c -= mod;
        }
    }
    inline T queryf(T& x,T& y){
        //return x + y;
        //return x * y;
        //return max(x, y);
        Node z(0,0,0);
        z.abc = x.abc + y.abc;
        if(z.abc>=mod)z.abc -= mod;
        z.ab = x.ab + y.ab;
        if(z.ab>=mod)z.ab -= mod;
        z.ac = x.ac + y.ac;
        if(z.ac>=mod)z.ac -= mod;
        z.bc = x.bc + y.bc;
        if(z.bc>=mod)z.bc -= mod;
        z.a = x.a + y.a;
        if(z.a>=mod)z.a -= mod;
        z.b = x.b + y.b;
        if(z.b>=mod)z.b -= mod;
        z.c = x.c + y.c;
        if(z.c>=mod)z.c -= mod;
        return z;
    }
public:
    LazySegmentTree(int sz,T nodeE,S lazyE ):E0(nodeE), E1(lazyE){
        n=1;
        while(n<sz)n<<=1;
        node.resize(2*n-1,E0);
        lazy.resize(2*n-1,E1);
    }

    LazySegmentTree(vector<T>& v,T E0,S E1 ):E0(E0),E1(E1){
        n=1;
        int sz=v.size();
        while(n<sz)n<<=1;
        node.resize(2*n-1,E0);
        lazy.resize(2*n-1,E1);
        rep(i,sz)node[i+n-1] = v[i];
        for(int i=n-2; i>=0; --i){
            node[i] = queryf(node[2*i+1],node[2*i+2]);
        }
    }

    void eval(int k,int l,int r){
        if(!lazy[k].a && !lazy[k].b && !lazy[k].c )return ;
        calculatef(node[k], lazy[k], r-l);
        if(r-l>1){
            updatef(lazy[2*k+1], lazy[k]);
            updatef(lazy[2*k+2], lazy[k]);
        }
        lazy[k]=E1;
    }

    void update(int a, int b, S x,int k=0,int l=0,int r=-1){
        if(r<0)r=n;
        eval(k,l,r);
        if(r<=a||b<=l)return;
        if(a<=l&&r<=b){
            updatef(lazy[k], x);
            eval(k,l,r);
        }
        else {
            update(a,b,x,2*k+1,l,(l+r)/2);
            update(a,b,x,2*k+2,(l+r)/2,r);
            node[k]=queryf(node[2*k+1], node[2*k+2]);
        }
    }

    T query(int a,int b,int k=0,int l=0,int r=-1){
        if(r<0)r=n;
        eval(k,l,r);
        if(r<=a||b<=l)return E0;
        if(a<=l&&r<=b)return node[k];
        T xl=query(a,b,2*k+1,l,(l+r)/2);
        T xr=query(a,b,2*k+2,(l+r)/2,r);
        return queryf(xl, xr);
    }
};
LazySegmentTree<Node, Op> sg(1,Node(0,0,0), {0,0,0});

struct HLDecomposition{
    int n,pos;
    vector<vector<int>> v;
    vector<int> idx,head,sz,hvy,par,depth,inv,type;
 
    HLDecomposition(){};
    HLDecomposition(int s):
        n(s),pos(0),v(n),idx(n,-1),head(n),sz(n,1),
        hvy(n,-1),par(n),depth(n),inv(n),type(n){}
     
    void addedge(int x,int y){
        v[x].push_back(y);
        v[y].push_back(x);
    }
 
    void dfs1(int rt){
        par[rt]=-1;
        depth[rt]=0;
        stack<pint> st;
        st.push({rt,0});
        while(!st.empty()){
            int x=st.top().first;
            int& i=st.top().second;
            if(i<(int)v[x].size()){
                int to=v[x][i++];
                if(to==par[x])continue;
                par[to]=x;
                depth[to]=depth[x]+1;
                st.push({to,0});
            }
            else {
                st.pop();
                int res=0;
                for(int to:v[x]){
                    if(to==par[x])continue;
                    sz[x]+=sz[to];
                    if(sz[to]>res)res=sz[to],hvy[x]=to;
                }
            }
        }
    }
    void dfs2(int r,int c){
        int &k=pos;
        stack<int> st;
        st.push(r);
        while(!st.empty()){
            int h=st.top();st.pop();
            for(int x=h;x!=-1;x=hvy[x]){
                type[x]=c;
                head[x]=h;
                idx[x]=k++;
                inv[idx[x]]=x;
                for(int to:v[x])
                    if(to!=par[x]&&to!=hvy[x])st.push(to);
            }
        }
    }
 
    void build(vector<int> rs=vector<int>(1,0)){
        int c=0;
        for(int r:rs){
            dfs1(r);
            dfs2(r,c++);
        }
    }
    void f(int x,int y, ll z){
        //ここに何か書く！！！
        sg.update(x,y+1, {0,z,mod-z});
    }
 
    /*void for_v(int x,int y){
        while(1){
            if(idx[x]>idx[y])swap(x,y);
            f(max(idx[head[y]],idx[x]),idx[y]);
            if(head[x]!=head[y])y=par[head[y]];
            else break;
        }
    }*/
 
    void for_edge(int x,int y, ll z){
        ll ret=0;
        while(1){
            if(idx[x]>idx[y])swap(x,y);
            if(head[x]!=head[y]){
                f(idx[head[y]],idx[y], z);
                y=par[head[y]];
            }
            else{
                if(x!=y)f(idx[x]+1,idx[y], z);
                break;
            }
        }
    }
    int lca(int x,int y){
        while(1){
            if(idx[x]>idx[y])swap(x,y);
            if(head[x]==head[y])return x;
            y=par[head[y]];
        }
    }
 
    int dist(int x,int y){
        return depth[x]+depth[y]-2*depth[lca(x,y)];
    }
};

vector<vector<pair<int,int>>> v(202020);
vector<ll> w(202020);
void dfs(int x, int p) {
    for(auto to : v[x]){
        if(to.first == p) continue;
        dfs(to.first, x);
        w[x] += w[to.first];
        if(w[x]>=mod)w[x]-=mod;
    }
}
int main(){
    int n;
    cin>>n;
    rep(i,n)cin>>w[i];
    HLDecomposition hl(n);
    vector<int> a(n-1), b(n-1), u(n-1);
    rep(i,n-1){
        int x,y,z;
        cin>>x>>y>>z;
        --x;--y;
        v[x].emplace_back(y,z);
        v[y].emplace_back(x,z);
        hl.addedge(x,y);
        a[i] = x;
        b[i] = y;
        u[i] = z;
    }
    dfs(0, -1);
    hl.build();
    vector<Node> node(n, Node(0,0,0));
    rep(i,n-1){
        if(hl.idx[a[i]]>hl.idx[b[i]])swap(a[i],b[i]);
        int id = hl.idx[b[i]];
        node[id] = Node(u[i],w[b[i]], (w[0]+mod-w[b[i]])%mod);
    }
    sg = LazySegmentTree<Node, Op>(node, Node(0,0,0), {0,0,0});
    int size = sg.n;
    cout << sg.query(0, size).abc << endl;
    int q;
    cin >> q;
    while(q--){
        int t, x, z;
        cin >> t >> x >> z;
        --x;
        if(t == 1) {
            sg.update(0,size, {0,0,z});
            hl.for_edge(0, x, z);

        } else {
            int id = hl.idx[b[x]];
            sg.update(id, id + 1, {z,0,0});
        }
        cout << sg.query(0,size).abc << endl;
    }
   return 0;
}
accuracy: 1
time_ms: 690
memory_kb: 98820
final_rank: 9

code_snippet: #include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<iomanip>
#include<math.h>
#include<complex>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#include<bitset>
using namespace std;
#define REP(i,m,n) for(int i=(int)m ; i < (int) n ; ++i )
#define rep(i,n) REP(i,0,n)
typedef long long ll;
typedef pair<int,int> pint;
typedef pair<ll,int> pli;
const int inf=1e9+7;
const ll longinf=1LL<<60 ;
const ll mod=998244353 ;
int dx[4]={1,0,-1,0} , dy[4]={0,1,0,-1} ;

struct Node {
    ll abc,ab,ac,bc,a,b,c;
    Node(ll a,ll b, ll c):a(a),b(b),c(c) {
        ab = a * b % mod;
        ac = a * c % mod;
        bc = b * c % mod;
        abc = ab * c % mod;
    }
};

struct Op {
    ll a, b, c;
};

template<typename T, typename S>
struct LazySegmentTree{
    int n;
    vector<T> node;
    vector<S> lazy;
    T E0;
    S E1;

    inline void updatef(S& lazy,S& value){
        //lazy += value;
        lazy.a += value.a;
        if(lazy.a >= mod) lazy.a -= mod;
        lazy.b += value.b;
        if(lazy.b >= mod) lazy.b -= mod;
        lazy.c += value.c;
        if(lazy.c >= mod) lazy.c -= mod;
        //lazy = max(lazy, value);
        //lazy = min(lazy, value);
    }
    inline void calculatef(T& node,S& lazy,int len){
        //node += lazy * len; //区間sumはこっち
        // node += lazy ; //区間maxとか
        if(lazy.a) {
            node.abc = (node.abc + node.bc * lazy.a) % mod;
            node.ab = (node.ab + node.b * lazy.a) % mod;
            node.ac = (node.ac + node.c * lazy.a) % mod;
            node.a += lazy.a;
            if(node.a >= mod)node.a -= mod;
        }
        if(lazy.b) {
            node.abc = (node.abc + node.ac * lazy.b) % mod;
            node.bc = (node.bc + node.c * lazy.b) % mod;
            node.ab = (node.ab + node.a * lazy.b) % mod;
            node.b += lazy.b;
            if(node.b >= mod)node.b -= mod;
        }
        if(lazy.c) {
            node.abc = (node.abc + node.ab * lazy.c) % mod;
            node.ac = (node.ac + node.a * lazy.c) % mod;
            node.bc = (node.bc + node.b * lazy.c) % mod;
            node.c += lazy.c;
            if(node.c >= mod)node.c -= mod;
        }
    }
    inline T queryf(T& x,T& y){
        //return x + y;
        //return x * y;
        //return max(x, y);
        Node z(0,0,0);
        z.abc = x.abc + y.abc;
        if(z.abc>=mod)z.abc -= mod;
        z.ab = x.ab + y.ab;
        if(z.ab>=mod)z.ab -= mod;
        z.ac = x.ac + y.ac;
        if(z.ac>=mod)z.ac -= mod;
        z.bc = x.bc + y.bc;
        if(z.bc>=mod)z.bc -= mod;
        z.a = x.a + y.a;
        if(z.a>=mod)z.a -= mod;
        z.b = x.b + y.b;
        if(z.b>=mod)z.b -= mod;
        z.c = x.c + y.c;
        if(z.c>=mod)z.c -= mod;
        return z;
    }
public:
    LazySegmentTree(int sz,T nodeE,S lazyE ):E0(nodeE), E1(lazyE){
        n=1;
        while(n<sz)n<<=1;
        node.resize(2*n-1,E0);
        lazy.resize(2*n-1,E1);
    }

    LazySegmentTree(vector<T>& v,T E0,S E1 ):E0(E0),E1(E1){
        n=1;
        int sz=v.size();
        while(n<sz)n<<=1;
        node.resize(2*n-1,E0);
        lazy.resize(2*n-1,E1);
        rep(i,sz)node[i+n-1] = v[i];
        for(int i=n-2; i>=0; --i){
            node[i] = queryf(node[2*i+1],node[2*i+2]);
        }
    }

    void eval(int k,int l,int r){
        if(!lazy[k].a && !lazy[k].b && !lazy[k].c )return ;
        calculatef(node[k], lazy[k], r-l);
        if(r-l>1){
            updatef(lazy[2*k+1], lazy[k]);
            updatef(lazy[2*k+2], lazy[k]);
        }
        lazy[k]=E1;
    }

    void update(int a, int b, S x,int k=0,int l=0,int r=-1){
        if(r<0)r=n;
        eval(k,l,r);
        if(r<=a||b<=l)return;
        if(a<=l&&r<=b){
            updatef(lazy[k], x);
            eval(k,l,r);
        }
        else {
            update(a,b,x,2*k+1,l,(l+r)/2);
            update(a,b,x,2*k+2,(l+r)/2,r);
            node[k]=queryf(node[2*k+1], node[2*k+2]);
        }
    }

    T query(int a,int b,int k=0,int l=0,int r=-1){
        if(r<0)r=n;
        eval(k,l,r);
        if(r<=a||b<=l)return E0;
        if(a<=l&&r<=b)return node[k];
        T xl=query(a,b,2*k+1,l,(l+r)/2);
        T xr=query(a,b,2*k+2,(l+r)/2,r);
        return queryf(xl, xr);
    }
};
LazySegmentTree<Node, Op> sg(1,Node(0,0,0), {0,0,0});

struct HLDecomposition{
    int n,pos;
    vector<vector<int>> v;
    vector<int> idx,head,sz,hvy,par,depth,inv,type;
 
    HLDecomposition(){};
    HLDecomposition(int s):
        n(s),pos(0),v(n),idx(n,-1),head(n),sz(n,1),
        hvy(n,-1),par(n),depth(n),inv(n),type(n){}
     
    void addedge(int x,int y){
        v[x].push_back(y);
        v[y].push_back(x);
    }
 
    void dfs1(int rt){
        par[rt]=-1;
        depth[rt]=0;
        stack<pint> st;
        st.push({rt,0});
        while(!st.empty()){
            int x=st.top().first;
            int& i=st.top().second;
            if(i<(int)v[x].size()){
                int to=v[x][i++];
                if(to==par[x])continue;
                par[to]=x;
                depth[to]=depth[x]+1;
                st.push({to,0});
            }
            else {
                st.pop();
                int res=0;
                for(int to:v[x]){
                    if(to==par[x])continue;
                    sz[x]+=sz[to];
                    if(sz[to]>res)res=sz[to],hvy[x]=to;
                }
            }
        }
    }
    void dfs2(int r,int c){
        int &k=pos;
        stack<int> st;
        st.push(r);
        while(!st.empty()){
            int h=st.top();st.pop();
            for(int x=h;x!=-1;x=hvy[x]){
                type[x]=c;
                head[x]=h;
                idx[x]=k++;
                inv[idx[x]]=x;
                for(int to:v[x])
                    if(to!=par[x]&&to!=hvy[x])st.push(to);
            }
        }
    }
 
    void build(vector<int> rs=vector<int>(1,0)){
        int c=0;
        for(int r:rs){
            dfs1(r);
            dfs2(r,c++);
        }
    }
    void f(int x,int y, ll z){
        //ここに何か書く！！！
        sg.update(x,y+1, {0,z,mod-z});
    }
 
    /*void for_v(int x,int y){
        while(1){
            if(idx[x]>idx[y])swap(x,y);
            f(max(idx[head[y]],idx[x]),idx[y]);
            if(head[x]!=head[y])y=par[head[y]];
            else break;
        }
    }*/
 
    void for_edge(int x,int y, ll z){
        ll ret=0;
        while(1){
            if(idx[x]>idx[y])swap(x,y);
            if(head[x]!=head[y]){
                f(idx[head[y]],idx[y], z);
                y=par[head[y]];
            }
            else{
                if(x!=y)f(idx[x]+1,idx[y], z);
                break;
            }
        }
    }
    int lca(int x,int y){
        while(1){
            if(idx[x]>idx[y])swap(x,y);
            if(head[x]==head[y])return x;
            y=par[head[y]];
        }
    }
 
    int dist(int x,int y){
        return depth[x]+depth[y]-2*depth[lca(x,y)];
    }
};

vector<vector<pair<int,int>>> v(202020);
vector<ll> w(202020);
void dfs(int x, int p) {
    for(auto to : v[x]){
        if(to.first == p) continue;
        dfs(to.first, x);
        w[x] += w[to.first];
        if(w[x]>=mod)w[x]-=mod;
    }
}
int main(){
    int n;
    cin>>n;
    rep(i,n)cin>>w[i];
    HLDecomposition hl(n);
    vector<int> a(n-1), b(n-1), u(n-1);
    rep(i,n-1){
        int x,y,z;
        cin>>x>>y>>z;
        --x;--y;
        v[x].emplace_back(y,z);
        v[y].emplace_back(x,z);
        hl.addedge(x,y);
        a[i] = x;
        b[i] = y;
        u[i] = z;
    }
    dfs(0, -1);
    hl.build();
    vector<Node> node(n, Node(0,0,0));
    rep(i,n-1){
        if(hl.idx[a[i]]>hl.idx[b[i]])swap(a[i],b[i]);
        int id = hl.idx[b[i]];
        node[id] = Node(u[i],w[b[i]]%mod, (w[0]-w[b[i]])%mod);
    }
    sg = LazySegmentTree<Node, Op>(node, Node(0,0,0), {0,0,0});
    int size = sg.n;
    cout << sg.query(0, size).abc << endl;
    int q;
    cin >> q;
    while(q--){
        int t, x, z;
        cin >> t >> x >> z;
        --x;
        if(t == 1) {
            sg.update(0,size, {0,0,z});
            hl.for_edge(0, x, z);

        } else {
            int id = hl.idx[b[x]];
            sg.update(id, id + 1, {z,0,0});
        }
        cout << sg.query(0,size).abc << endl;
    }
   return 0;
}
accuracy: 0.07692307692307693
time_ms: 670
memory_kb: 88424
final_rank: 12

code_snippet: #include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<iomanip>
#include<math.h>
#include<complex>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#include<bitset>
using namespace std;
#define REP(i,m,n) for(int i=(int)m ; i < (int) n ; ++i )
#define rep(i,n) REP(i,0,n)
typedef long long ll;
typedef pair<int,int> pint;
typedef pair<ll,int> pli;
const int inf=1e9+7;
const ll longinf=1LL<<60 ;
const ll mod=998244353 ;
int dx[4]={1,0,-1,0} , dy[4]={0,1,0,-1} ;

struct Node {
    ll abc,ab,ac,bc,a,b,c;
    Node(ll a,ll b, ll c):a(a),b(b),c(c) {
        ab = a * b % mod;
        ac = a * c % mod;
        bc = b * c % mod;
        abc = ab * c % mod;
    }
};

struct Op {
    ll a, b, c;
};

template<typename T, typename S>
struct LazySegmentTree{
    int n;
    vector<T> node;
    vector<S> lazy;
    T E0;
    S E1;

    inline void updatef(S& lazy,S& value){
        //lazy += value;
        lazy.a += value.a;
        if(lazy.a >= mod) lazy.a -= mod;
        lazy.b += value.b;
        if(lazy.b >= mod) lazy.b -= mod;
        lazy.c += value.c;
        if(lazy.c >= mod) lazy.c -= mod;
        //lazy = max(lazy, value);
        //lazy = min(lazy, value);
    }
    inline void calculatef(T& node,S& lazy,int len){
        //node += lazy * len; //区間sumはこっち
        // node += lazy ; //区間maxとか
        if(lazy.a) {
            node.abc = (node.abc + node.bc * lazy.a) % mod;
            node.ab = (node.ab + node.b * lazy.a) % mod;
            node.ac = (node.ac + node.c * lazy.a) % mod;
            node.a += lazy.a;
            if(node.a >= mod)node.a -= mod;
        }
        if(lazy.b) {
            node.abc = (node.abc + node.ac * lazy.b) % mod;
            node.bc = (node.bc + node.c * lazy.b) % mod;
            node.ab = (node.ab + node.a * lazy.b) % mod;
            node.b += lazy.b;
            if(node.b >= mod)node.b -= mod;
        }
        if(lazy.c) {
            node.abc = (node.abc + node.ab * lazy.c) % mod;
            node.ac = (node.ac + node.a * lazy.c) % mod;
            node.bc = (node.bc + node.b * lazy.c) % mod;
            node.c += lazy.c;
            if(node.c >= mod)node.c -= mod;
        }
    }
    inline T queryf(T& x,T& y){
        //return x + y;
        //return x * y;
        //return max(x, y);
        Node z(0,0,0);
        z.abc = x.abc + y.abc;
        if(z.abc>=mod)z.abc -= mod;
        z.ab = x.ab + y.ab;
        if(z.ab>=mod)z.ab -= mod;
        z.ac = x.ac + y.ac;
        if(z.ac>=mod)z.ac -= mod;
        z.bc = x.bc + y.bc;
        if(z.bc>=mod)z.bc -= mod;
        z.a = x.a + y.a;
        if(z.a>=mod)z.a -= mod;
        z.b = x.b + y.b;
        if(z.b>=mod)z.b -= mod;
        z.c = x.c + y.c;
        if(z.c>=mod)z.c -= mod;
        return z;
    }
public:
    LazySegmentTree(int sz,T nodeE,S lazyE ):E0(nodeE), E1(lazyE){
        n=1;
        while(n<sz)n<<=1;
        node.resize(2*n-1,E0);
        lazy.resize(2*n-1,E1);
    }

    LazySegmentTree(vector<T>& v,T E0,S E1 ):E0(E0),E1(E1){
        n=1;
        int sz=v.size();
        while(n<sz)n<<=1;
        node.resize(2*n-1,E0);
        lazy.resize(2*n-1,E1);
        rep(i,sz)node[i+n-1] = v[i];
        for(int i=n-2; i>=0; --i){
            node[i] = queryf(node[2*i+1],node[2*i+2]);
        }
    }

    void eval(int k,int l,int r){
        if(!lazy[k].a && !lazy[k].b && !lazy[k].c )return ;
        calculatef(node[k], lazy[k], r-l);
        if(r-l>1){
            updatef(lazy[2*k+1], lazy[k]);
            updatef(lazy[2*k+2], lazy[k]);
        }
        lazy[k]=E1;
    }

    void update(int a, int b, S x,int k=0,int l=0,int r=-1){
        if(r<0)r=n;
        eval(k,l,r);
        if(r<=a||b<=l)return;
        if(a<=l&&r<=b){
            updatef(lazy[k], x);
            eval(k,l,r);
        }
        else {
            update(a,b,x,2*k+1,l,(l+r)/2);
            update(a,b,x,2*k+2,(l+r)/2,r);
            node[k]=queryf(node[2*k+1], node[2*k+2]);
        }
    }

    T query(int a,int b,int k=0,int l=0,int r=-1){
        if(r<0)r=n;
        eval(k,l,r);
        if(r<=a||b<=l)return E0;
        if(a<=l&&r<=b)return node[k];
        T xl=query(a,b,2*k+1,l,(l+r)/2);
        T xr=query(a,b,2*k+2,(l+r)/2,r);
        return queryf(xl, xr);
    }
};
LazySegmentTree<Node, Op> sg(1,Node(0,0,0), {0,0,0});

struct HLDecomposition{
    int n,pos;
    vector<vector<int>> v;
    vector<int> idx,head,sz,hvy,par,depth,inv,type;
 
    HLDecomposition(){};
    HLDecomposition(int s):
        n(s),pos(0),v(n),idx(n,-1),head(n),sz(n,1),
        hvy(n,-1),par(n),depth(n),inv(n),type(n){}
     
    void addedge(int x,int y){
        v[x].push_back(y);
        v[y].push_back(x);
    }
 
    void dfs1(int rt){
        par[rt]=-1;
        depth[rt]=0;
        stack<pint> st;
        st.push({rt,0});
        while(!st.empty()){
            int x=st.top().first;
            int& i=st.top().second;
            if(i<(int)v[x].size()){
                int to=v[x][i++];
                if(to==par[x])continue;
                par[to]=x;
                depth[to]=depth[x]+1;
                st.push({to,0});
            }
            else {
                st.pop();
                int res=0;
                for(int to:v[x]){
                    if(to==par[x])continue;
                    sz[x]+=sz[to];
                    if(sz[to]>res)res=sz[to],hvy[x]=to;
                }
            }
        }
    }
    void dfs2(int r,int c){
        int &k=pos;
        stack<int> st;
        st.push(r);
        while(!st.empty()){
            int h=st.top();st.pop();
            for(int x=h;x!=-1;x=hvy[x]){
                type[x]=c;
                head[x]=h;
                idx[x]=k++;
                inv[idx[x]]=x;
                for(int to:v[x])
                    if(to!=par[x]&&to!=hvy[x])st.push(to);
            }
        }
    }
 
    void build(vector<int> rs=vector<int>(1,0)){
        int c=0;
        for(int r:rs){
            dfs1(r);
            dfs2(r,c++);
        }
    }
    void f(int x,int y, ll z){
        //ここに何か書く！！！
        sg.update(x,y+1, {0,z,mod-z});
    }
 
    /*void for_v(int x,int y){
        while(1){
            if(idx[x]>idx[y])swap(x,y);
            f(max(idx[head[y]],idx[x]),idx[y]);
            if(head[x]!=head[y])y=par[head[y]];
            else break;
        }
    }*/
 
    void for_edge(int x,int y, ll z){
        ll ret=0;
        while(1){
            if(idx[x]>idx[y])swap(x,y);
            if(head[x]!=head[y]){
                f(idx[head[y]],idx[y], z);
                y=par[head[y]];
            }
            else{
                if(x!=y)f(idx[x]+1,idx[y], z);
                break;
            }
        }
    }
    int lca(int x,int y){
        while(1){
            if(idx[x]>idx[y])swap(x,y);
            if(head[x]==head[y])return x;
            y=par[head[y]];
        }
    }
 
    int dist(int x,int y){
        return depth[x]+depth[y]-2*depth[lca(x,y)];
    }
};

vector<vector<pair<int,int>>> v(202020);
vector<ll> w(202020);
void dfs(int x, int p) {
    for(auto to : v[x]){
        if(to.first == p) continue;
        dfs(to.first, x);
        w[x] += w[to.first];
        if(w[x]>=mod)w[x]-=mod;
    }
}
int main(){
    int n;
    cin>>n;
    rep(i,n)cin>>w[i];
    HLDecomposition hl(n);
    vector<int> a(n-1), b(n-1), u(n-1);
    rep(i,n-1){
        int x,y,z;
        cin>>x>>y>>z;
        --x;--y;
        v[x].emplace_back(y,z);
        v[y].emplace_back(x,z);
        hl.addedge(x,y);
        a[i] = x;
        b[i] = y;
        u[i] = z;
    }
    dfs(0, -1);
    hl.build();
    vector<Node> node(n, Node(0,0,0));
    rep(i,n-1){
        if(hl.idx[a[i]]>hl.idx[b[i]])swap(a[i],b[i]);
        int id = hl.idx[b[i]];
        node[id] = Node(u[i],w[b[i]], w[0]-w[b[i]]);
    }
    sg = LazySegmentTree<Node, Op>(node, Node(0,0,0), {0,0,0});
    int size = sg.n;
    cout << sg.query(0, size).abc << endl;
    int q;
    cin >> q;
    while(q--){
        int t, x, z;
        cin >> t >> x >> z;
        --x;
        if(t == 1) {
            sg.update(0,size, {0,0,z});
            hl.for_edge(0, x, z);

        } else {
            int id = hl.idx[b[x]];
            sg.update(id, id + 1, {z,0,0});
        }
        cout << sg.query(0,size).abc << endl;
    }
   return 0;
}
accuracy: 0.07692307692307693
time_ms: 750
memory_kb: 88384
final_rank: 13