#define PROBLEM "https://judge.yosupo.jp/problem/range_parallel_unionfind"
//#include"../../template/template.hpp"//#include"../../data-structure/parallel-union-find.hpp"//#include"../../modint/montgomery-modint.hpp"//usingnamespaceNyaan;usingmint=LazyMontgomeryModInt<998244353>;// using mint = LazyMontgomeryModInt<1000000007>;usingvm=vector<mint>;usingvvm=vector<vm>;usingnamespaceNyaan;voidq(){ini(N,Q);vmX(N);in(X);ParallelUnionFinduf(N);mintans=0;rep(i,Q){inl(k,a,b);uf.unite(a,a+k,b,b+k,[&](intx,inty){ans+=X[x]*X[y];X[x]+=X[y];});out(ans);}}voidNyaan::solve(){intt=1;// in(t);while(t--)q();}
#line 1 "verify/verify-yosupo-ds/yosupo-range-parallel-unionfind.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/range_parallel_unionfind"
//#line 2 "template/template.hpp"
usingnamespacestd;// intrinstic#include<immintrin.h>#include<algorithm>
#include<array>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cfenv>
#include<cfloat>
#include<chrono>
#include<cinttypes>
#include<climits>
#include<cmath>
#include<complex>
#include<cstdarg>
#include<cstddef>
#include<cstdint>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<deque>
#include<fstream>
#include<functional>
#include<initializer_list>
#include<iomanip>
#include<ios>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<random>
#include<set>
#include<sstream>
#include<stack>
#include<streambuf>
#include<string>
#include<tuple>
#include<type_traits>
#include<typeinfo>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<vector>// utility#line 3 "template/util.hpp"
namespaceNyaan{usingll=longlong;usingi64=longlong;usingu64=unsignedlonglong;usingi128=__int128_t;usingu128=__uint128_t;template<typenameT>usingV=vector<T>;template<typenameT>usingVV=vector<vector<T>>;usingvi=vector<int>;usingvl=vector<longlong>;usingvd=V<double>;usingvs=V<string>;usingvvi=vector<vector<int>>;usingvvl=vector<vector<longlong>>;template<typenameT>usingminpq=priority_queue<T,vector<T>,greater<T>>;template<typenameT,typenameU>structP:pair<T,U>{template<typename...Args>P(Args...args):pair<T,U>(args...){}usingpair<T,U>::first;usingpair<T,U>::second;P&operator+=(constP&r){first+=r.first;second+=r.second;return*this;}P&operator-=(constP&r){first-=r.first;second-=r.second;return*this;}P&operator*=(constP&r){first*=r.first;second*=r.second;return*this;}template<typenameS>P&operator*=(constS&r){first*=r,second*=r;return*this;}Poperator+(constP&r)const{returnP(*this)+=r;}Poperator-(constP&r)const{returnP(*this)-=r;}Poperator*(constP&r)const{returnP(*this)*=r;}template<typenameS>Poperator*(constS&r)const{returnP(*this)*=r;}Poperator-()const{returnP{-first,-second};}};usingpl=P<ll,ll>;usingpi=P<int,int>;usingvp=V<pl>;constexprintinf=1001001001;constexprlonglonginfLL=4004004004004004004LL;template<typenameT>intsz(constT&t){returnt.size();}template<typenameT,typenameU>inlineboolamin(T&x,Uy){return(y<x)?(x=y,true):false;}template<typenameT,typenameU>inlineboolamax(T&x,Uy){return(x<y)?(x=y,true):false;}template<typenameT>inlineTMax(constvector<T>&v){return*max_element(begin(v),end(v));}template<typenameT>inlineTMin(constvector<T>&v){return*min_element(begin(v),end(v));}template<typenameT>inlinelonglongSum(constvector<T>&v){returnaccumulate(begin(v),end(v),0LL);}template<typenameT>intlb(constvector<T>&v,constT&a){returnlower_bound(begin(v),end(v),a)-begin(v);}template<typenameT>intub(constvector<T>&v,constT&a){returnupper_bound(begin(v),end(v),a)-begin(v);}constexprlonglongTEN(intn){longlongret=1,x=10;for(;n;x*=x,n>>=1)ret*=(n&1?x:1);returnret;}template<typenameT,typenameU>pair<T,U>mkp(constT&t,constU&u){returnmake_pair(t,u);}template<typenameT>vector<T>mkrui(constvector<T>&v,boolrev=false){vector<T>ret(v.size()+1);if(rev){for(inti=int(v.size())-1;i>=0;i--)ret[i]=v[i]+ret[i+1];}else{for(inti=0;i<int(v.size());i++)ret[i+1]=ret[i]+v[i];}returnret;};template<typenameT>vector<T>mkuni(constvector<T>&v){vector<T>ret(v);sort(ret.begin(),ret.end());ret.erase(unique(ret.begin(),ret.end()),ret.end());returnret;}template<typenameF>vector<int>mkord(intN,Ff){vector<int>ord(N);iota(begin(ord),end(ord),0);sort(begin(ord),end(ord),f);returnord;}template<typenameT>vector<int>mkinv(vector<T>&v){intmax_val=*max_element(begin(v),end(v));vector<int>inv(max_val+1,-1);for(inti=0;i<(int)v.size();i++)inv[v[i]]=i;returninv;}vector<int>mkiota(intn){vector<int>ret(n);iota(begin(ret),end(ret),0);returnret;}template<typenameT>Tmkrev(constT&v){Tw{v};reverse(begin(w),end(w));returnw;}template<typenameT>boolnxp(T&v){returnnext_permutation(begin(v),end(v));}// 返り値の型は入力の T に依存// i 要素目 : [0, a[i])template<typenameT>vector<vector<T>>product(constvector<T>&a){vector<vector<T>>ret;vector<T>v;autodfs=[&](autorc,inti)->void{if(i==(int)a.size()){ret.push_back(v);return;}for(intj=0;j<a[i];j++)v.push_back(j),rc(rc,i+1),v.pop_back();};dfs(dfs,0);returnret;}// F : void(T&), mod を取る操作// T : 整数型のときはオーバーフローに注意するtemplate<typenameT,typenameF>TPower(Ta,longlongn,constT&I,F&&f){static_assert(std::is_invocable_r_v<void,F&,T&>,"Power callback must be callable as void(T&)");Tres=I;for(;n;std::invoke(f,a=a*a),n>>=1){if(n&1)std::invoke(f,res=res*a);}returnres;}// T : 整数型のときはオーバーフローに注意するtemplate<typenameT>TPower(Ta,longlongn,constT&I=T{1}){autono_op=[](T&)->void{};returnPower(a,n,I,no_op);}template<typenameT>TRev(constT&v){Tres=v;reverse(begin(res),end(res));returnres;}template<typenameT>vector<T>Transpose(constvector<T>&v){usingU=typenameT::value_type;if(v.empty())return{};intH=v.size(),W=v[0].size();vectorres(W,T(H,U{}));for(inti=0;i<H;i++){for(intj=0;j<W;j++){res[j][i]=v[i][j];}}returnres;}template<typenameT>vector<T>Rotate(constvector<T>&v,intclockwise=true){usingU=typenameT::value_type;intH=v.size(),W=v[0].size();vectorres(W,T(H,U{}));for(inti=0;i<H;i++){for(intj=0;j<W;j++){if(clockwise){res[W-1-j][i]=v[i][j];}else{res[j][H-1-i]=v[i][j];}}}returnres;}}// namespace Nyaan#line 58 "template/template.hpp"
// bit operation#line 1 "template/bitop.hpp"
namespaceNyaan{__attribute__((target("popcnt")))inlineintpopcnt(constu64&a){return__builtin_popcountll(a);}inlineintlsb(constu64&a){returna?__builtin_ctzll(a):64;}inlineintctz(constu64&a){returna?__builtin_ctzll(a):64;}inlineintmsb(constu64&a){returna?63-__builtin_clzll(a):-1;}template<typenameT>inlineintgbit(constT&a,inti){return(a>>i)&1;}template<typenameT>inlinevoidsbit(T&a,inti,boolb){if(gbit(a,i)!=b)a^=T(1)<<i;}constexprlonglongPW(intn){return1LL<<n;}constexprlonglongMSK(intn){return(1LL<<n)-1;}}// namespace Nyaan#line 61 "template/template.hpp"
// inout#line 1 "template/inout.hpp"
namespaceNyaan{template<typenameT,typenameU>ostream&operator<<(ostream&os,constpair<T,U>&p){os<<p.first<<" "<<p.second;returnos;}template<typenameT,typenameU>istream&operator>>(istream&is,pair<T,U>&p){is>>p.first>>p.second;returnis;}template<typenameT>ostream&operator<<(ostream&os,constvector<T>&v){ints=(int)v.size();for(inti=0;i<s;i++)os<<(i?" ":"")<<v[i];returnos;}template<typenameT>istream&operator>>(istream&is,vector<T>&v){for(auto&x:v)is>>x;returnis;}istream&operator>>(istream&is,__int128_t&x){stringS;is>>S;x=0;intflag=0;for(auto&c:S){if(c=='-'){flag=true;continue;}x*=10;x+=c-'0';}if(flag)x=-x;returnis;}istream&operator>>(istream&is,__uint128_t&x){stringS;is>>S;x=0;for(auto&c:S){x*=10;x+=c-'0';}returnis;}ostream&operator<<(ostream&os,__int128_tx){if(x==0)returnos<<0;if(x<0)os<<'-',x=-x;stringS;while(x)S.push_back('0'+x%10),x/=10;reverse(begin(S),end(S));returnos<<S;}ostream&operator<<(ostream&os,__uint128_tx){if(x==0)returnos<<0;stringS;while(x)S.push_back('0'+x%10),x/=10;reverse(begin(S),end(S));returnos<<S;}voidin(){}template<typenameT,class...U>voidin(T&t,U&...u){cin>>t;in(u...);}voidout(){cout<<"\n";}template<typenameT,class...U,charsep=' '>voidout(constT&t,constU&...u){cout<<t;if(sizeof...(u))cout<<sep;out(u...);}structIoSetupNya{IoSetupNya(){cin.tie(nullptr);ios::sync_with_stdio(false);cout<<fixed<<setprecision(15);cerr<<fixed<<setprecision(7);}}iosetupnya;}// namespace Nyaan#line 64 "template/template.hpp"
// debug#line 1 "template/debug.hpp"
namespaceDebugImpl{template<typenameU,typename=void>structis_specialize:false_type{};template<typenameU>structis_specialize<U,typenameconditional<false,typenameU::iterator,void>::type>:true_type{};template<typenameU>structis_specialize<U,typenameconditional<false,decltype(U::first),void>::type>:true_type{};template<typenameU>structis_specialize<U,enable_if_t<is_integral<U>::value,void>>:true_type{};voiddump(constchar&t){cerr<<t;}voiddump(conststring&t){cerr<<t;}voiddump(constbool&t){cerr<<(t?"true":"false");}voiddump(__int128_tt){if(t==0)cerr<<0;if(t<0)cerr<<'-',t=-t;stringS;while(t)S.push_back('0'+t%10),t/=10;reverse(begin(S),end(S));cerr<<S;}voiddump(__uint128_tt){if(t==0)cerr<<0;stringS;while(t)S.push_back('0'+t%10),t/=10;reverse(begin(S),end(S));cerr<<S;}template<typenameU,enable_if_t<!is_specialize<U>::value,nullptr_t>=nullptr>voiddump(constU&t){cerr<<t;}template<typenameT>voiddump(constT&t,enable_if_t<is_integral<T>::value>*=nullptr){stringres;if(t==Nyaan::inf)res="inf";ifconstexpr(is_signed<T>::value){if(t==-Nyaan::inf)res="-inf";}ifconstexpr(sizeof(T)==8){if(t==Nyaan::infLL)res="inf";ifconstexpr(is_signed<T>::value){if(t==-Nyaan::infLL)res="-inf";}}if(res.empty())res=to_string(t);cerr<<res;}template<typenameT,typenameU>voiddump(constpair<T,U>&);template<typenameT>voiddump(constpair<T*,int>&);template<typenameT>voiddump(constT&t,enable_if_t<!is_void<typenameT::iterator>::value>*=nullptr){cerr<<"[ ";for(autoit=t.begin();it!=t.end();){dump(*it);cerr<<(++it==t.end()?"":", ");}cerr<<" ]";}template<typenameT,typenameU>voiddump(constpair<T,U>&t){cerr<<"( ";dump(t.first);cerr<<", ";dump(t.second);cerr<<" )";}template<typenameT>voiddump(constpair<T*,int>&t){cerr<<"[ ";for(inti=0;i<t.second;i++){dump(t.first[i]);cerr<<(i==t.second-1?"":", ");}cerr<<" ]";}voidtrace(){cerr<<endl;}template<typenameHead,typename...Tail>voidtrace(Head&&head,Tail&&...tail){cerr<<" ";dump(head);if(sizeof...(tail)!=0)cerr<<",";trace(std::forward<Tail>(tail)...);}}// namespace DebugImpl#ifdef NyaanDebug
#define trc(...) \
do { \
cerr << "## " << #__VA_ARGS__ << " = "; \
DebugImpl::trace(__VA_ARGS__); \
} while (0)
#else
#define trc(...) (void(0))
#endif
#ifdef NyaanLocal
#define trc2(...) \
do { \
cerr << "## " << #__VA_ARGS__ << " = "; \
DebugImpl::trace(__VA_ARGS__); \
} while (0)
#else
#define trc2(...) (void(0))
#endif
#line 67 "template/template.hpp"
// macro#line 1 "template/macro.hpp"
#define each(x, v) for (auto&& x : v)
#define each2(x, y, v) for (auto&& [x, y] : v)
#define all(v) (v).begin(), (v).end()
#define rep(i, N) for (long long i = 0; i < (long long)(N); i++)
#define repr(i, N) for (long long i = (long long)(N)-1; i >= 0; i--)
#define rep1(i, N) for (long long i = 1; i <= (long long)(N); i++)
#define repr1(i, N) for (long long i = (N); (long long)(i) > 0; i--)
#define reg(i, a, b) for (long long i = (a); i < (b); i++)
#define regr(i, a, b) for (long long i = (b)-1; i >= (a); i--)
#define fi first
#define se second
#define ini(...) \
int __VA_ARGS__; \
in(__VA_ARGS__)
#define inl(...) \
long long __VA_ARGS__; \
in(__VA_ARGS__)
#define ins(...) \
string __VA_ARGS__; \
in(__VA_ARGS__)
#define in2(s, t) \
for (int i = 0; i < (int)s.size(); i++) { \
in(s[i], t[i]); \
}
#define in3(s, t, u) \
for (int i = 0; i < (int)s.size(); i++) { \
in(s[i], t[i], u[i]); \
}
#define in4(s, t, u, v) \
for (int i = 0; i < (int)s.size(); i++) { \
in(s[i], t[i], u[i], v[i]); \
}
#define die(...) \
do { \
Nyaan::out(__VA_ARGS__); \
return; \
} while (0)
#line 70 "template/template.hpp"
namespaceNyaan{voidsolve();}intmain(){Nyaan::solve();}#line 4 "verify/verify-yosupo-ds/yosupo-range-parallel-unionfind.test.cpp"
//#line 2 "data-structure/parallel-union-find.hpp"
#line 2 "string/rolling-hash-on-segment-tree.hpp"
#line 4 "string/rolling-hash-on-segment-tree.hpp"
usingnamespacestd;#line 1 "atcoder/segtree.hpp"
#line 8 "atcoder/segtree.hpp"
#line 1 "atcoder/internal_bit.hpp"
#ifdef _MSC_VER
#include<intrin.h>
#endif
#if __cplusplus >= 202002L
#include<bit>
#endif
namespaceatcoder{namespaceinternal{#if __cplusplus >= 202002L
usingstd::bit_ceil;#else
// @return same with std::bit::bit_ceilunsignedintbit_ceil(unsignedintn){unsignedintx=1;while(x<(unsignedint)(n))x*=2;returnx;}#endif
// @param n `1 <= n`// @return same with std::bit::countr_zerointcountr_zero(unsignedintn){#ifdef _MSC_VER
unsignedlongindex;_BitScanForward(&index,n);returnindex;#else
return__builtin_ctz(n);#endif
}// @param n `1 <= n`// @return same with std::bit::countr_zeroconstexprintcountr_zero_constexpr(unsignedintn){intx=0;while(!(n&(1<<x)))x++;returnx;}}// namespace internal}// namespace atcoder#line 10 "atcoder/segtree.hpp"
namespaceatcoder{#if __cplusplus >= 201703L
template<classS,autoop,autoe>structsegtree{static_assert(std::is_convertible_v<decltype(op),std::function<S(S,S)>>,"op must work as S(S, S)");static_assert(std::is_convertible_v<decltype(e),std::function<S()>>,"e must work as S()");#else
template<classS,S(*op)(S,S),S(*e)()>structsegtree{#endif
public:segtree():segtree(0){}explicitsegtree(intn):segtree(std::vector<S>(n,e())){}explicitsegtree(conststd::vector<S>&v):_n(int(v.size())){size=(int)internal::bit_ceil((unsignedint)(_n));log=internal::countr_zero((unsignedint)size);d=std::vector<S>(2*size,e());for(inti=0;i<_n;i++)d[size+i]=v[i];for(inti=size-1;i>=1;i--){update(i);}}voidset(intp,Sx){assert(0<=p&&p<_n);p+=size;d[p]=x;for(inti=1;i<=log;i++)update(p>>i);}Sget(intp)const{assert(0<=p&&p<_n);returnd[p+size];}Sprod(intl,intr)const{assert(0<=l&&l<=r&&r<=_n);Ssml=e(),smr=e();l+=size;r+=size;while(l<r){if(l&1)sml=op(sml,d[l++]);if(r&1)smr=op(d[--r],smr);l>>=1;r>>=1;}returnop(sml,smr);}Sall_prod()const{returnd[1];}template<bool(*f)(S)>intmax_right(intl)const{returnmax_right(l,[](Sx){returnf(x);});}template<classF>intmax_right(intl,Ff)const{assert(0<=l&&l<=_n);assert(f(e()));if(l==_n)return_n;l+=size;Ssm=e();do{while(l%2==0)l>>=1;if(!f(op(sm,d[l]))){while(l<size){l=(2*l);if(f(op(sm,d[l]))){sm=op(sm,d[l]);l++;}}returnl-size;}sm=op(sm,d[l]);l++;}while((l&-l)!=l);return_n;}template<bool(*f)(S)>intmin_left(intr)const{returnmin_left(r,[](Sx){returnf(x);});}template<classF>intmin_left(intr,Ff)const{assert(0<=r&&r<=_n);assert(f(e()));if(r==0)return0;r+=size;Ssm=e();do{r--;while(r>1&&(r%2))r>>=1;if(!f(op(d[r],sm))){while(r<size){r=(2*r+1);if(f(op(d[r],sm))){sm=op(d[r],sm);r--;}}returnr+1-size;}sm=op(d[r],sm);}while((r&-r)!=r);return0;}private:int_n,size,log;std::vector<S>d;voidupdate(intk){d[k]=op(d[2*k],d[2*k+1]);}};}// namespace atcoder#line 2 "internal/internal-hash.hpp"
namespacenyaan_internal{usingi64=longlong;usingu64=unsignedlonglong;usingu128=__uint128_t;template<intBASE_NUM=2>structHash:array<u64,BASE_NUM>{usingarray<u64,BASE_NUM>::operator[];staticconstexprintn=BASE_NUM;Hash():array<u64,BASE_NUM>(){}staticconstexpru64md=(1ull<<61)-1;constexprstaticHashset(consti64&a){Hashres;fill(begin(res),end(res),cast(a));returnres;}Hash&operator+=(constHash&r){for(inti=0;i<n;i++)if(((*this)[i]+=r[i])>=md)(*this)[i]-=md;return*this;}Hash&operator+=(consti64&r){u64s=cast(r);for(inti=0;i<n;i++)if(((*this)[i]+=s)>=md)(*this)[i]-=md;return*this;}Hash&operator-=(constHash&r){for(inti=0;i<n;i++)if(((*this)[i]+=md-r[i])>=md)(*this)[i]-=md;return*this;}Hash&operator-=(consti64&r){u64s=cast(r);for(inti=0;i<n;i++)if(((*this)[i]+=md-s)>=md)(*this)[i]-=md;return*this;}Hash&operator*=(constHash&r){for(inti=0;i<n;i++)(*this)[i]=modmul((*this)[i],r[i]);return*this;}Hash&operator*=(consti64&r){u64s=cast(r);for(inti=0;i<n;i++)(*this)[i]=modmul((*this)[i],s);return*this;}Hashoperator+(constHash&r){returnHash(*this)+=r;}Hashoperator+(consti64&r){returnHash(*this)+=r;}Hashoperator-(constHash&r){returnHash(*this)-=r;}Hashoperator-(consti64&r){returnHash(*this)-=r;}Hashoperator*(constHash&r){returnHash(*this)*=r;}Hashoperator*(consti64&r){returnHash(*this)*=r;}Hashoperator-()const{Hashres;for(inti=0;i<n;i++)res[i]=(*this)[i]==0?0:md-(*this)[i];returnres;}friendHashpfma(constHash&a,constHash&b,constHash&c){Hashres;for(inti=0;i<n;i++)res[i]=modfma(a[i],b[i],c[i]);returnres;}friendHashpfma(constHash&a,constHash&b,consti64&c){Hashres;u64s=cast(c);for(inti=0;i<n;i++)res[i]=modfma(a[i],b[i],s);returnres;}Hashpow(longlonge){Hasha{*this},res{Hash::set(1)};for(;e;a*=a,e>>=1){if(e&1)res*=a;}returnres;}staticHashget_basis(){staticautorand_time=chrono::duration_cast<chrono::nanoseconds>(chrono::high_resolution_clock::now().time_since_epoch()).count();staticmt19937_64rng(rand_time);Hashh;for(inti=0;i<n;i++){while(isPrimitive(h[i]=rng()%(md-1)+1)==false);}returnh;}private:staticu64modpow(u64a,u64b){u64r=1;for(a%=md;b;a=modmul(a,a),b>>=1)r=modmul(r,a);returnr;}staticboolisPrimitive(u64x){for(auto&d:vector<u64>{2,3,5,7,11,13,31,41,61,151,331,1321})if(modpow(x,(md-1)/d)<=1)returnfalse;returntrue;}staticinlineconstexpru64cast(constlonglong&a){returna<0?a+md:a;}staticinlineconstexpru64modmul(constu64&a,constu64&b){u128d=u128(a)*b;u64ret=(u64(d)&md)+u64(d>>61);returnret>=md?ret-md:ret;}staticinlineconstexpru64modfma(constu64&a,constu64&b,constu64&c){u128d=u128(a)*b+c;u64ret=(d>>61)+(u64(d)&md);returnret>=md?ret-md:ret;}};}// namespace nyaan_internal/**
* @brief ハッシュ構造体
*/#line 8 "string/rolling-hash-on-segment-tree.hpp"
namespaceRollingHashonSegmentTreeImpl{constexprintBASE_NUM=1;usingHash=nyaan_internal::Hash<BASE_NUM>;usingT=pair<Hash,int>;vector<Hash>Pow{Hash::set(1)};constHashBasis=Hash::get_basis();constHashZero=Hash::set(0);Top(Ta,Tb){while(b.second>=(int)Pow.size()){Hashh=Pow.back();Pow.push_back(h*Basis);}Hashh=pfma(a.first,Pow[b.second],b.first);intlen=a.second+b.second;returnmake_pair(h,len);}Te(){returnmake_pair(Zero,0);}template<typenameStr>structRollingHashonSegmentTree{usingValue=typenameStr::value_type;intn;atcoder::segtree<T,op,e>seg;RollingHashonSegmentTree():n(0){}RollingHashonSegmentTree(constStr&S):n(S.size()){vector<T>init(n);for(inti=0;i<n;i++){init[i]=make_pair(Hash::set(S[i]),1);}seg=atcoder::segtree<T,op,e>(init);}voidupdate(inti,constValue&v){assert(0<=iandi<n);seg.set(i,make_pair(Hash::set(v),1));}// [l1, r1) と [l2, r2) が一致するかを判定boolsame(intl1,intr1,intl2,intr2){assert(0<=l1andl1<=r1andr1<=n);assert(0<=l2andl2<=r2andr2<=n);if(r1-l1!=r2-l2)returnfalse;returnseg.prod(l1,r1)==seg.prod(l2,r2);}};}// namespace RollingHashonSegmentTreeImplusingRollingHashonSegmentTreeImpl::RollingHashonSegmentTree;#line 2 "data-structure/union-find-enumerate.hpp"
#line 4 "data-structure/union-find-enumerate.hpp"
usingnamespacestd;structUnionFindEnumerate{vector<int>data,nxt;UnionFindEnumerate(intN):data(N,-1),nxt(N){for(inti=0;i<N;i++)nxt[i]=i;}intfind(intk){returndata[k]<0?k:data[k]=find(data[k]);}intunite(intx,inty){if((x=find(x))==(y=find(y)))returnfalse;if(data[x]>data[y])swap(x,y);data[x]+=data[y];data[y]=x;swap(nxt[x],nxt[y]);returntrue;}// f(x, y) : x に y をマージtemplate<typenameF>intunite(intx,inty,constF&f){if((x=find(x))==(y=find(y)))returnfalse;if(data[x]>data[y])swap(x,y);data[x]+=data[y];data[y]=x;f(x,y);swap(nxt[x],nxt[y]);returntrue;}intsize(intk){return-data[find(k)];}intsame(intx,inty){returnfind(x)==find(y);}vector<int>enumerate(inti){vector<int>res{i};for(intj=nxt[i];j!=i;j=nxt[j])res.push_back(j);returnres;}};#line 5 "data-structure/parallel-union-find.hpp"
structParallelUnionFind{intn;UnionFindEnumerateuf;RollingHashonSegmentTree<vector<int>>seg;ParallelUnionFind(int_n):n(_n),uf(n){vector<int>init(n);for(inti=0;i<n;i++)init[i]=i;seg=RollingHashonSegmentTree<vector<int>>(init);}// [l1, r1) と [l2, r2) を unite するvoidunite(intl1,intr1,intl2,intr2){assert(0<=l1andl1<=r1andr1<=n);assert(0<=l2andl2<=r2andr2<=n);assert(r1-l1==r2-l2);while(1){if(seg.same(l1,r1,l2,r2))break;intok=0,ng=r1-l1;while(ok+1<ng){intm=(ok+ng)/2;(seg.same(l1,l1+m,l2,l2+m)?ok:ng)=m;}uf.unite(l1+ok,l2+ok,[&](intx,inty){for(intz:uf.enumerate(y))seg.update(z,x);});}}// [l1, r1) と [l2, r2) を unite する// f(x, y) : x に y をマージtemplate<typenameF>voidunite(intl1,intr1,intl2,intr2,constF&f){assert(0<=l1andl1<=r1andr1<=n);assert(0<=l2andl2<=r2andr2<=n);assert(r1-l1==r2-l2);while(1){if(seg.same(l1,r1,l2,r2))break;intok=0,ng=r1-l1;while(ok+1<ng){intm=(ok+ng)/2;(seg.same(l1,l1+m,l2,l2+m)?ok:ng)=m;}uf.unite(l1+ok,l2+ok,[&](intx,inty){for(intz:uf.enumerate(y))seg.update(z,x);f(x,y);});}}voidunite(intl,intr){unite(l,l+1,r,r+1);}intfind(inti){returnuf.find(i);}intsame(intl,intr){returnuf.same(l,r);}intsize(inti){returnuf.size(i);}};#line 6 "verify/verify-yosupo-ds/yosupo-range-parallel-unionfind.test.cpp"
//#line 2 "modint/montgomery-modint.hpp"
#line 5 "modint/montgomery-modint.hpp"
template<uint32_tmod>structLazyMontgomeryModInt{usingmint=LazyMontgomeryModInt;usingi32=int32_t;usingu32=uint32_t;usingu64=uint64_t;staticconstexpru32get_r(){u32ret=mod;for(i32i=0;i<4;++i)ret*=2-mod*ret;returnret;}staticconstexpru32r=get_r();staticconstexpru32n2=-u64(mod)%mod;static_assert(mod<(1<<30),"invalid, mod >= 2 ^ 30");static_assert((mod&1)==1,"invalid, mod % 2 == 0");static_assert(r*mod==1,"this code has bugs.");u32a;constexprLazyMontgomeryModInt():a(0){}constexprLazyMontgomeryModInt(constint64_t&b):a(reduce(u64(b%mod+mod)*n2)){};staticconstexpru32reduce(constu64&b){return(b+u64(u32(b)*u32(-r))*mod)>>32;}constexprmint&operator+=(constmint&b){if(i32(a+=b.a-2*mod)<0)a+=2*mod;return*this;}constexprmint&operator-=(constmint&b){if(i32(a-=b.a)<0)a+=2*mod;return*this;}constexprmint&operator*=(constmint&b){a=reduce(u64(a)*b.a);return*this;}constexprmint&operator/=(constmint&b){*this*=b.inverse();return*this;}constexprmintoperator+(constmint&b)const{returnmint(*this)+=b;}constexprmintoperator-(constmint&b)const{returnmint(*this)-=b;}constexprmintoperator*(constmint&b)const{returnmint(*this)*=b;}constexprmintoperator/(constmint&b)const{returnmint(*this)/=b;}constexprbooloperator==(constmint&b)const{return(a>=mod?a-mod:a)==(b.a>=mod?b.a-mod:b.a);}constexprbooloperator!=(constmint&b)const{return(a>=mod?a-mod:a)!=(b.a>=mod?b.a-mod:b.a);}constexprmintoperator-()const{returnmint()-mint(*this);}constexprmintoperator+()const{returnmint(*this);}constexprmintpow(u64n)const{mintret(1),mul(*this);while(n>0){if(n&1)ret*=mul;mul*=mul;n>>=1;}returnret;}constexprmintinverse()const{intx=get(),y=mod,u=1,v=0,t=0,tmp=0;while(y>0){t=x/y;x-=t*y,u-=t*v;tmp=x,x=y,y=tmp;tmp=u,u=v,v=tmp;}returnmint{u};}friendstd::ostream&operator<<(std::ostream&os,constmint&b){returnos<<b.get();}friendstd::istream&operator>>(std::istream&is,mint&b){int64_tt;is>>t;b=LazyMontgomeryModInt<mod>(t);return(is);}constexpru32get()const{u32ret=reduce(a);returnret>=mod?ret-mod:ret;}staticconstexpru32get_mod(){returnmod;}};#line 8 "verify/verify-yosupo-ds/yosupo-range-parallel-unionfind.test.cpp"
//usingnamespaceNyaan;usingmint=LazyMontgomeryModInt<998244353>;// using mint = LazyMontgomeryModInt<1000000007>;usingvm=vector<mint>;usingvvm=vector<vm>;usingnamespaceNyaan;voidq(){ini(N,Q);vmX(N);in(X);ParallelUnionFinduf(N);mintans=0;rep(i,Q){inl(k,a,b);uf.unite(a,a+k,b,b+k,[&](intx,inty){ans+=X[x]*X[y];X[x]+=X[y];});out(ans);}}voidNyaan::solve(){intt=1;// in(t);while(t--)q();}