#ifndef MYLOCAL //# pragma GCC target("avx2")//yukiではNG # pragma GCC optimize("O3") # pragma GCC optimize("unroll-loops") #endif #if defined(NDEBUG) #undef NDEBUG #endif #include "bits/stdc++.h" using namespace std; using ll=long long; using dd=long double; using pll=pair; using tll=tuple; using qll=tuple; using namespace chrono; constexpr ll INF = 1201001001001001001; struct Fast{ Fast(){ cin.tie(0); ios::sync_with_stdio(false); cout<::max_digits10); } } fast; #define EXPAND( x ) x//VS用おまじない #define overload3(_1,_2,_3,name,...) name #define overload4(_1,_2,_3,_4,name,...) name #define overload5(_1,_2,_3,_4,_5,name,...) name #define rep1(N) for (ll dmyi = 0; dmyi < (N); dmyi++) #define rep2(i, N) for (ll i = 0; i < (N); i++) #define rep3(i, S, E) for (ll i = (S); i <= (E); i++) #define rep4(i, S, E, t) for (ll i = (S); i <= (E); i+=(t)) #define rep(...) EXPAND(overload4(__VA_ARGS__,rep4,rep3,rep2,rep1)(__VA_ARGS__)) #define dep3(i, E, S) for (ll i = (E); i >= (S); i--) #define dep4(i, E, S, t) for (ll i = (E); i >= (S); i-=(t)) #define dep(...) EXPAND(overload4(__VA_ARGS__, dep4, dep3,_,_)(__VA_ARGS__)) #define ALL1(v) (v).begin(), (v).end() #define ALL2(v,E) (v).begin(), (v).begin()+((E)+1) #define ALL3(v,S,E) (v).begin()+(S), (v).begin()+((E)+1) #define all(...) EXPAND(overload3(__VA_ARGS__, ALL3, ALL2, ALL1)(__VA_ARGS__)) template inline bool chmax(T &a, T b) { if (a < b) { a = b; return true; }return false; } template inline bool chmin(T &a, T b) { if (a > b) { a = b; return true; }return false; } template [[nodiscard]] inline T limithi(T a,T b){ return min(a,b); } template [[nodiscard]] inline T limitlo(T a,T b){ return max(a,b); } template inline bool chlimithi(T &a,T b){ return chmin(a,b); } template inline bool chlimitlo(T &a,T b){ return chmax(a,b); } template inline auto maxe(T &&v,ll S,ll E){ return *max_element(all(v,S,E)); } template inline auto maxe(T &&v){ return *max_element(all(v)); } template inline auto mine(T &&v,ll S,ll E){ return *min_element(all(v,S,E)); } template inline auto mine(T &&v){ return *min_element(all(v)); } template::type::value_type> inline U sum(T &&v,ll S,ll E) {return accumulate(all(v,S,E),U());} template inline auto sum(T &&v) {return sum(v,0,v.end()-v.begin()-1);} template inline ll sz(T &&v){ return (ll)v.size(); } //cin struct cinutil{ template static void cin1core(T &a){ cin>>a; } template static void cin1core(pair &a){ cin1core(a.first),cin1core(a.second); } template static void cin1core(tuple &a){ cinTplRec,sizeof...(Args)-1>()(a); } template static void cin1core(array &a){ for (int i=0; i<(int)N; ++i) cin>>a[i]; } private: template struct cinTplRec{ void operator()(Tpl &a){ cinTplRec()(a); cin1core(get(a)); } }; template struct cinTplRec{ void operator()(Tpl &a){ cin1core(get<0>(a)); } }; }; template T cin1(){ T a; cinutil::cin1core(a); return a; } template tuple cins(){ return cin1>(); } //cout template inline ostream &operator<<(ostream &os,const pair &a){ return os << a.first << ' ' << a.second; } template inline ostream &operator<<(ostream &os,const tuple &a){ return os << get<0>(a) << ' ' << get<1>(a) << ' ' << get<2>(a); } template inline ostream &operator<<(ostream &os,const tuple &a){ return os << get<0>(a) << ' ' << get<1>(a) << ' ' << get<2>(a) << ' ' << get<3>(a); } template inline ostream &operator<<(ostream &os,const vector &a){ for (ll i=0; i<(ll)a.size(); i++) os<<(i>0?" ":"")<(system_clock::now()-st).count()/1000;} } timeget; template struct mll_{ using Int = long long; using ll = long long; ll val_=0; /*---- utility ----*/ mll_ &norm(){ return normR().normS(); }//正規化 mll_ &normR(){ val_%=MOD; return *this; }//剰余正規化のみ mll_ &normS(){ if (val_<0) val_+=MOD; return *this; }//正負正規化のみ mll_ &normP(){ if (val_>=MOD) val_-=MOD; return *this; }//加算時正規化 mll_ &invsg(){ val_=-val_; return normS(); }//正負反転 ll modinv(int a){//a^-1 mod MOD int ypre=0,y=1,apre=MOD; while (a>1){ int t=apre/a; apre-=a*t,swap(a,apre); ypre-=y*t,swap(y,ypre); } return y<0 ? y+MOD : y; } /*---- I/F ----*/ mll_(){} mll_(ll v): val_(v){ norm(); } mll_(ll v,bool b): val_(v){} //正規化無のコンストラクタ Int val()const{ return (Int)val_; } bool isnone() const { return val_==-1; } //true:値なし mll_ &none() { val_=-1; return *this; } //値なしにする mll_ &inv(){ val_=modinv((int)val_); return *this; } mll_ &operator+=(mll_ b){ val_+=b.val_; return normP(); } mll_ &operator-=(mll_ b){ val_-=b.val_; return normS(); } mll_ &operator*=(mll_ b){ val_*=b.val_; return normR(); } mll_ &operator/=(mll_ b){ return *this*=b.inv(); } mll_ &operator+=(ll b){ return *this+=mll_(b); } mll_ &operator-=(ll b){ return *this-=mll_(b); } mll_ &operator*=(ll b){ return *this*=mll_(b); } mll_ &operator/=(ll b){ return *this/=mll_(b); } mll_ operator-()const{ return mll_(*this).invsg(); } mll_ operator+(mll_ b)const{ return mll_(*this)+=b; } mll_ operator-(mll_ b)const{ return mll_(*this)-=b; } mll_ operator*(mll_ b)const{ return mll_(*this)*=b; } mll_ operator/(mll_ b)const{ return mll_(*this)/=b; } mll_ operator+(ll b)const{ return mll_(*this)+=b; } mll_ operator-(ll b)const{ return mll_(*this)-=b; } mll_ operator*(ll b)const{ return mll_(*this)*=b; } mll_ operator/(ll b)const{ return mll_(*this)/=b; } friend mll_ operator+(ll a,mll_ b){ return b+a; } friend mll_ operator-(ll a,mll_ b){ return -b+a; } friend mll_ operator*(ll a,mll_ b){ return b*a; } friend mll_ operator/(ll a,mll_ b){ return mll_(a)/b; } bool operator==(mll_ b)const{ return val_==b.val_; } bool operator!=(mll_ b)const{ return val_!=b.val_; } bool operator==(ll b)const{ return *this==mll_(b); } bool operator!=(ll b)const{ return *this!=mll_(b); } friend bool operator==(ll a,mll_ b){ return mll_(a)==b; } friend bool operator!=(ll a,mll_ b){ return mll_(a)!=b; } friend ostream &operator<<(ostream &os,mll_ a){ return os << a.val_; } friend istream &operator>>(istream &is,mll_ &a){ return is >> a.val_; } mll_ pow(ll k)const{ mll_ ret(1,false),a(*this); for (; k>0; k>>=1,a*=a) if (k&1)ret*=a; return ret; } static constexpr int mod() { return MOD; } //enum{ modll=MOD }; }; template struct Vector: vector{ using Int = long long; using vT=vector; using cvT=const vector; using cT=const T; using vT::vT; //親クラスのコンストラクタの隠蔽を回避 using vT::begin,vT::end,vT::insert,vT::erase; auto it(Int i){ return begin()+i; } auto it(Int i)const{ return begin()+i; } Vector(cvT& b):vT(b){} Vector(vT&& b):vT(move(b)){} Vector(int n,cT& x):vT(n,x){}// ┬ 型推論のためラッパー Vector(long long n,cT& x):vT(n,x){} template Vector(const Vector& b):vT(b.begin(),b.end()){} template Vector(const vector& b):vT(b.begin(),b.end()){} Vector(Int n,T s,T d){ iota(n,s,d); } Vector(Int n,function g):vT(n){ for(Int i=0;i &b){ return *this+=(cvT&)b; } Vector &operator-=(const Vector &b){ return *this-=(cvT&)b; } Vector &operator*=(const Vector &b){ return *this*=(cvT&)b; } Vector &operator/=(const Vector &b){ return *this/=(cvT&)b; } Vector &operator%=(const Vector &b){ return *this%=(cvT&)b; } Vector operator+(cvT &b){ return Vector(*this)+=b; } Vector operator-(cvT &b){ return Vector(*this)-=b; } Vector operator*(cvT &b){ return Vector(*this)*=b; } Vector operator/(cvT &b){ return Vector(*this)/=b; } Vector operator%(cvT &b){ return Vector(*this)%=b; } Vector operator+(const Vector &b){ return Vector(*this)+=b; } Vector operator-(const Vector &b){ return Vector(*this)-=b; } Vector operator*(const Vector &b){ return Vector(*this)*=b; } Vector operator/(const Vector &b){ return Vector(*this)/=b; } Vector operator%(const Vector &b){ return Vector(*this)%=b; } template Vector &operator+=(S x){ for(T &e: *this) e+=x; return *this; } template Vector &operator-=(S x){ for(T &e: *this) e-=x; return *this; } template Vector &operator*=(S x){ for(T &e: *this) e*=x; return *this; } template Vector &operator/=(S x){ for(T &e: *this) e/=x; return *this; } template Vector &operator%=(S x){ for(T &e: *this) e%=x; return *this; } template Vector operator+(S x)const{ return Vector(*this)+=x; } template Vector operator-(S x)const{ return Vector(*this)-=x; } template Vector operator*(S x)const{ return Vector(*this)*=x; } template Vector operator/(S x)const{ return Vector(*this)/=x; } template Vector operator%(S x)const{ return Vector(*this)%=x; } Vector &operator--(int){ return *this-=1; } Vector &operator++(int){ return *this+=1; } Vector operator-()const{ return Vector(*this)*=-1; } template friend Vector operator-(S x,const Vector &a){ return -a+=x; } T& at(Int i){ assert(i>=0); if(n()<=i)vT::resize(i+1); return vT::operator[](i); } Vector slice(Int l,Int r,Int d=1)const{ Vector ret; for(Int i=l;(d>0&&i<=r)||(d<0&&r<=i);i+=d) ret.push_back((*this)[i]); return ret; } Int size()const{ return (Int)vT::size(); } Int n()const{ return size(); } Vector &push_back(cT& x,Int n=1){ for(Int i=0;iinsert(0,x,n); return *this; } Vector &pop_front(Int n=1){ erase(0,n-1); return *this; } T pull_back(){ T x=move(vT::back()); vT::pop_back(); return x; } T pull_front(){ T x=move(vT::front()); erase(0); return x; } Vector &insert(Int i,cT& x,Int n=1){ insert(it(i),n,x); return *this; } Vector &insert(Int i,cvT& b){ insert(it(i),b.begin(),b.end()); return *this; } Vector &erase(Int i){ erase(it(i)); return *this; } Vector &erase(Int l,Int r){ erase(it(l),it(r+1)); return *this; } Vector &erase(const Vector &idxs){ for (Int I=0; In(); copy(it(l),it(r),it(l-I-1));//[l,r)を前にI+1個ずらす } vT::resize(this->n()-idxs.n()); return *this; } Vector &eraseall(cT& x){ return eraseall(0,size()-1,x); } Vector &eraseall(Int l,Int r,cT& x){ erase(remove(it(l),it(r+1),x),it(r+1)); return *this; } template Vector &eraseif(Pr pr){ return eraseif(0,size()-1,pr); } template Vector &eraseif(Int l,Int r,Pr pr){ erase(remove_if(it(l),it(r+1),pr),it(r+1)); return *this; } Vector &concat(cvT &b,Int n=1){ cvT B = (&b==this) ? *this : vT{}; for(int i=0;iinsert(size(),(&b==this)?B:b); return *this; } Vector repeat(Int n){ return Vector{}.concat(*this,n); } Vector &reverse(Int l=0,Int r=-1){ r+=r<0?size():0; std::reverse(it(l),it(r+1)); return *this; } Vector &rotate(Int m){ return rotate(0,size()-1,m); } Vector &rotate(Int l,Int r,Int m){ std::rotate(it(l),it(m),it(r+1)); return *this; } Vector &sort(Int l=0,Int r=-1){ r+=r<0?size():0; std::sort(it(l),it(r+1)); return *this; } Vector &rsort(Int l=0,Int r=-1){ return sort(l,r).reverse(l,r); } template Vector &sort(Pr pr){ return sort(0,size()-1,pr); } template Vector &sort(Int l,Int r,Pr pr){ std::sort(it(l),it(r+1),pr); return *this; } template Vector &sortbykey(Int l=0,Int r=-1){ r+=r<0?size():0; sort(l,r,[](cT &x,cT &y){return get(x)(y);}); return *this; } Vector &uniq(){ erase(unique(begin(),end()),end()); return *this; } Vector &sortq(){ return sort().uniq(); } Vector &fill(cT& x){ return fill(0,size()-1,x); } Vector &fill(Int l,Int r,cT& x){ std::fill(it(l),it(r+1),x); return *this; } Vector ©(Int i,cvT &b,Int n=1){//A[i]スタートでbをn回分コピー for (int t=0; t=size()) return *this; if (i>=0) (*this)[i]=b[j]; i++; } return *this; } template Vector &iota(Int n,T s=0,S d=1){ vT::resize(n); if(n==0) return *this; (*this)[0]=s; for(int i=1;i Int countif(Pr pr)const{ return countif(0,size()-1,pr); } template Int countif(Int l,Int r,Pr pr)const{ return Int(count_if(it(l),it(r+1),pr)); } Int find(cT& x)const{ return find(0,size()-1,x); } Int find(Int l,Int r,cT& x)const{ return Int(std::find(it(l),it(r+1),x)-begin()); } Int rfind(cT& x)const{ return rfind(0,size()-1,x); } Int rfind(Int l,Int r,cT& x)const{ for (int i=r;i>=l;--i) if ((*this)[i]==x) return i; return l-1; } template Int findif(Pr pr)const{ return findif(0,size()-1,pr); } template Int findif(Int l,Int r,Pr pr)const{ return Int(find_if(it(l),it(r+1),pr)-begin()); } Vector findall(cT& x)const{ return findall(0,size()-1,x); } Vector findall(Int l,Int r,cT& x)const{ return findallif(l,r,[&](cT& y){return y==x;}); } template Vector findallif(Pr pr)const{ return findallif(0,size()-1,pr); } template Vector findallif(Int l,Int r,Pr pr)const{ Vector ret; for(Int i=l;i<=r;++i) if(pr((*this)[i])) ret.push_back(i); return ret; } Int flooridx(cT& x)const{ return Int(upper_bound(begin(),end(),x)-begin()-1); } Int ceilidx(cT& x)const{ return Int(lower_bound(begin(),end(),x)-begin()); } Int leftnmof(cT& x)const{ return flooridx(x)+1; } Int rightnmof(cT& x)const{ return size()-ceilidx(x); } bool contains(cT& x)const{ Int i=flooridx(x); return i>=0 && (*this)[i]==x; } template Int flooridx(cT& x,Pr pr)const{ return Int(upper_bound(begin(),end(),x,pr)-begin()-1); } template Int ceilidx(cT& x,Pr pr)const{ return Int(lower_bound(begin(),end(),x,pr)-begin()); } template Int leftnmof(cT& x,Pr pr)const{ return flooridx(x,pr)+1; } template Int rightnmof(cT& x,Pr pr)const{ return size()-ceilidx(x,pr); } template bool contains(cT& x,Pr pr)const{ Int i=flooridx(x,pr); return i>=0 && (*this)[i]==x; } template using VV = Vector>; template using sVV = vector>; template using VVV = Vector>; template using sVVV = vector>; template using VVVV = Vector>; template using sVVVV = vector>; template using VVVVV = Vector>; template using sVVVVV = vector>; auto tostd()const{ return tov(*this); } template static vector tov(const Vector&v){ return v; } template static sVV tov(const VV &v){ sVV ret; for(auto&& e:v) ret.push_back(e); return ret; } template static sVVV tov(const VVV &v){ sVVV ret; for(auto&& e:v) ret.push_back(e.tostd()); return ret; } template static sVVVV tov(const VVVV &v){ sVVVV ret; for(auto&& e:v) ret.push_back(e.tostd()); return ret; } template static sVVVVV tov(const VVVVV &v){ sVVVVV ret; for(auto&& e:v) ret.push_back(e.tostd()); return ret; } }; #if 0 #define MODLL (1000000007LL) #else #define MODLL (998244353LL) #endif using mll = mll_; //using mll = fraction; namespace SolvingSpace{ template using vector = Vector; using vll=vector< ll>; using vmll=vector< mll>; using vdd=vector< dd>; using vvll=vector< vll>; using vvmll=vector< vmll>; using vvdd=vector< vdd>; using vvvll=vector< vvll>; using vvvmll=vector< vvmll>; using vvvdd=vector< vvdd>; using vvvvll=vector; using vvvvmll=vector; using vvvvdd=vector; using vpll=vector< pll>; using vtll=vector< tll>; using vqll=vector< qll>; using vvpll=vector< vpll>; using vvtll=vector< vtll>; using vvqll=vector< vqll>; using vss=vector; template vector cinv(ll nm){ return vector(nm,[](ll i){ (void)i; return cin1(); }); } template vector> cinvv(ll H,ll W){ return vector>(H,[&](ll i){ (void)i; return cinv(W); }); } /*■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■*/ //generated by GPT-5.4, modified by hamamu template struct lazyDynamicSegTree{ using Int = long long; using ll = long long; using cT = const T; using cF = const F; Ope ope; // データ同士の合成 Mapping rawMapping; // 生の作用: mapping(f,x,l,r) 区間は閉区間 [l,r] Composition rawComposition; // 生の作用素合成: composition(g,f) は f の後に g T e; // データの単位元 F id; // 作用素の単位元 ll B; // 添字範囲は [0, 2^B-1] 根/葉の深さがB/0 int rootid=-1; ll offset,offsetOrg; ll xr=0; // 全添字に仮想的に xor する値 struct Node{ T x; // 部分木の集約値。自ノードの laz は反映済み F laz; // 子孫へ未伝播の作用。葉では常に id array cids={-1,-1}; Node(cT &e,cF &id):x(e),laz(id){} ll nChild()const{ return 2-(cids[0]==-1)-(cids[1]==-1); } }; vector pool; lazyDynamicSegTree( T,F,Int B,T e,F id,Ope ope,Mapping mapping,Composition composition,Int offset=0 ):ope(ope),rawMapping(mapping),rawComposition(composition), e(e),id(id),B(B),offset(offset),offsetOrg(offset) { assert(B>=1); rootid=newNode(); } void clear(){ pool.clear(); rootid=newNode(); offset=offsetOrg; xr=0; } ll imin()const{ return offset; } ll imax()const{ return (1LL< floor(ll i)const{ auto [pos,val]=FloorLeaf(normalizeR(i),rootid,0,(1LL<{imin()-1,e} : pair{pos+offset,val}; } // i 以上で最小の生成済み位置とその値を返す。なければ {imax()+1, e}。 pair ceil(ll i)const{ auto [pos,val]=CeilLeaf(normalizeL(i),rootid,0,(1LL<{imax()+1,e} : pair{pos+offset,val}; } // 最小の生成済み位置とその値を返す。空なら {imax()+1, e}。 pair front()const{ auto [pos,val]=FirstLeaf(rootid,0,(1LL<{imax()+1,e} : pair{pos+offset,val}; } // 最大の生成済み位置とその値を返す。空なら {imin()-1, e}。 pair back()const{ auto [pos,val]=LastLeaf(rootid,0,(1LL<{imin()-1,e} : pair{pos+offset,val}; } // 点代入。存在しない点なら新規作成する。 void set(ll i,cT &x){ assert(IsIn(i)); ll j=toInner(i); ll s=toStored(j); Set(rootid,s,0,(1LL< ll minRight(ll l,ll R,IsOK isOK)const{ assert(!isOK(e)); ll nl=normalizeL(l); ll nR=normalizeR(R); if (nR ll maxRight(ll l,ll R,IsOK isOK)const{ ll pos=minRight(l,R,[&](const T &prd){ return !isOK(prd); }); return max(pos-1,l-1); } // [p,r] が初めて true になる最右の p。なければ L-1 template ll maxLeft(ll L,ll r,IsOK isOK)const{ assert(!isOK(e)); ll nL=normalizeL(L); ll nr=normalizeR(r); if (nr ll minLeft(ll L,ll r,IsOK isOK)const{ ll pos=maxLeft(L,r,[&](const T &prd){ return !isOK(prd); }); return min(pos+1,r+1); } // 生成済み葉だけ列挙する。 // 祖先の lazy は carry に積んで読み、木自体は書き換えない。 // 列挙順は格納座標順ではなく、xor 後の「見かけ上の添字昇順」。 vector> enumerate()const{ vector> ret; auto dfs=[&](auto dfs,int v,ll sl,ll sr,ll d,F carry)->void{ if (v==-1) return; const Node &nd=node(v); if (d==0){ // 葉に着いたら、祖先からの carry を反映した見かけ上の値を返す。 ll i=storedBlockL(sl,d)+offset; ret.emplace_back(i,mapping(carry,nd.x,i,i)); return; } // 子へ降りるときは、自ノードの laz を carry に積む。 F nextCarry=composition(carry,nd.laz); // low/high は「見かけ上の昇順」で並んでいる。 auto ch=orderedChildren(v,sl,sr,d); if (ch.low.cid !=-1) dfs(dfs,ch.low.cid,ch.low.sl,ch.low.sr,d-1,nextCarry); if (ch.high.cid!=-1) dfs(dfs,ch.high.cid,ch.high.sl,ch.high.sr,d-1,nextCarry); }; dfs(dfs,rootid,0,(1LL< tov()const{ vector ret(1LL< offset を外した内部添字 ll toInner(ll i)const{ return i-offset; } // 内部添字 -> 実際に木へ格納する座標 // xorAllIndex は木の組み替えではなく、この対応だけを変える。 ll toStored(ll i)const{ return i^xr; } // 深さ d のノード [sl,sr] が表す「見かけ上の連続区間」の左端。 // 下位 d bit はブロック内で自由に動くため、xor の影響は上位側だけで決まる。 ll storedBlockL(ll sl,ll d)const{ return ((sl>>d)^(xr>>d))<>(d-1))&1) ? 1 : 0; return takeHigh ? (lowBit^1) : lowBit; } struct ChildInfo{ int cid; ll sl,sr; // 格納座標上の区間 }; struct OrderedChildren{ ChildInfo low; // 見かけ上の昇順で先に来る子 ChildInfo high; // 見かけ上の昇順で後に来る子 }; // ノード v の 2 子を、xor 後の見かけ上の昇順に並べて返す OrderedChildren orderedChildren(int v,ll sl,ll sr,ll d)const{ assert(d>=1); ll sm=(sl+sr)>>1; int lowBit=childOrderBit(d,false); int highBit=lowBit^1; OrderedChildren ret; ret.low={ node(v).cids[lowBit], lowBit==0 ? sl : sm+1, lowBit==0 ? sm : sr }; ret.high={ node(v).cids[highBit], highBit==0 ? sl : sm+1, highBit==0 ? sm : sr }; return ret; } // ノード v 全体へ作用 f を掛ける。sl,sr は格納座標上の区間。 // ここでは subtree 全体が一様に更新されるので、x をまとめて更新し、 // 子孫への遅延は laz に積むだけでよい。 void AllApply(int v,cF &f,ll sl,ll sr,ll d){ Node &nd=node(v); ll l=storedBlockL(sl,d)+offset; ll r=storedBlockR(sl,d)+offset; nd.x = mapping(f,nd.x,l,r); if (d==0) nd.laz=id; else nd.laz=composition(f,nd.laz); } // v の未伝播 lazy を「既存の子にだけ」配る。 // sparse 実装なので、更新のために新しい子は作らない。 void Push(int v,ll sl,ll sr,ll d){ Node &nd=node(v); if (d==0 || IsId(nd.laz)) return; ll sm=(sl+sr)>>1; if (nd.cids[0]!=-1) AllApply(nd.cids[0],nd.laz,sl,sm,d-1); if (nd.cids[1]!=-1) AllApply(nd.cids[1],nd.laz,sm+1,sr,d-1); nd.laz=id; } // cids[bit] が未生成なら新規ノードを作る。点代入で新しい葉を生やすときだけ使う。 int EnsureChild(int v,int bit){ int cid=node(v).cids[bit]; if (cid==-1){ cid=newNode(); node(v).cids[bit]=cid; } return cid; } // 子の x から親の x を再計算する。 // xr!=0 のときも x 自体は格納座標順で持つため、 // xor 利用時は ope が順序入れ替えに耐えることが前提。 void Pull(int v){ Node &nd=node(v); T lx = nd.cids[0]==-1 ? e : node(nd.cids[0]).x; T rx = nd.cids[1]==-1 ? e : node(nd.cids[1]).x; nd.x = ope(lx,rx); } // 格納座標 s の葉を x にする。 // 書き込み系なので、途中で必要な lazy は Push してから降りる。 void Set(int v,ll s,ll sl,ll sr,ll d,cT &x){ if (d==0){ Node &nd=node(v); nd.x=x; nd.laz=id; // 葉の laz は常に id return; } Push(v,sl,sr,d); ll sm=(sl+sr)>>1; if (s<=sm){ int cid=EnsureChild(v,0); Set(cid,s,sl,sm,d-1,x); } else{ int cid=EnsureChild(v,1); Set(cid,s,sm+1,sr,d-1,x); } Pull(v); } // 位置 s の葉が存在するかだけを調べる。 // 値が e かどうかではなく、葉ノードがあるかで判定する。 bool Exists(int v,ll s,ll sl,ll sr,ll d)const{ if (v==-1) return false; if (d==0) return true; ll sm=(sl+sr)>>1; if (s<=sm) return Exists(node(v).cids[0],s,sl,sm,d-1); else return Exists(node(v).cids[1],s,sm+1,sr,d-1); } // 位置 s の葉を削除し、空になった部分木は親からも切り離す。 // 戻り値: // true -> この部分木全体が空になった // false -> まだこの部分木内に葉が残っている bool Erase(int v,ll s,ll sl,ll sr,ll d){ if (v==-1) return true; if (d==0){ // 葉を削除。pool 上のノード自体は残すが、親から切れば外からは到達しない。 Node &nd=node(v); nd.x=e; nd.laz=id; return true; } // 子の状態を正しく保つため、潜る前に未伝播 lazy を既存の子へ配る。 Push(v,sl,sr,d); ll sm=(sl+sr)>>1; int bit=(s<=sm ? 0 : 1); int cid=node(v).cids[bit]; // そもそもその子がなければ、消すものはない。 if (cid==-1) return node(v).nChild()==0; bool childEmpty; if (bit==0) childEmpty=Erase(cid,s,sl,sm,d-1); else childEmpty=Erase(cid,s,sm+1,sr,d-1); // 子部分木が空になったら、親から参照を切る。 if (childEmpty) node(v).cids[bit]=-1; if (node(v).nChild()==0){ // 自分も空部分木になった。 Node &nd=node(v); nd.x=e; nd.laz=id; return true; } // まだ葉が残るなら、子から親の x を再構築する。 Pull(v); return false; } // 部分木 v の中で、見かけ上もっとも左にある生成済み葉を返す。 // 返り値の位置は内部添字系 [0, 2^B-1] で、見つからなければ {2^B, e}。 pair FirstLeaf(int v,ll sl,ll sr,ll d,F carry)const{ if (v==-1) return {1LL< LastLeaf(int v,ll sl,ll sr,ll d,F carry)const{ if (v==-1) return {-1,e}; const Node &nd=node(v); if (d==0){ ll i=storedBlockL(sl,d); return {i,mapping(carry,nd.x,i+offset,i+offset)}; } // 自ノードの lazy を carry に積んでから、見かけ上右の子を優先して降りる。 carry=composition(carry,nd.laz); auto ch=orderedChildren(v,sl,sr,d); // 見かけ上右の子を優先し、見つからなければ左の子へ進む。 auto ret=LastLeaf(ch.high.cid,ch.high.sl,ch.high.sr,d-1,carry); if (ret.first!=-1) return ret; return LastLeaf(ch.low.cid,ch.low.sl,ch.low.sr,d-1,carry); } // 見かけ上の添字で a 以上にある生成済み葉のうち、最小のものを探す。 // 戻り値: // {pos,val} 見つかった葉 // {1LL< CeilLeaf(ll a,int v,ll sl,ll sr,ll d,F carry)const{ if (v==-1) return {1LL< FloorLeaf(ll b,int v,ll sl,ll sr,ll d,F carry)const{ if (v==-1) return {-1,e}; ll l=storedBlockL(sl,d); ll r=storedBlockR(sl,d); // この部分木全体が b より右にあるなら候補なし。 if (b>1; ApplyRange(node(v).cids[0],a,b,sl,sm,d-1,f); ApplyRange(node(v).cids[1],a,b,sm+1,sr,d-1,f); Pull(v); } // a,b は見かけ上の添字 // carry は祖先から降ってきた未伝播作用 // 木は書き換えず、carry に積んで読む T Prod(ll a,ll b,int v,ll sl,ll sr,ll d,F carry)const{ if (v==-1) return e; ll l=storedBlockL(sl,d); ll r=storedBlockR(sl,d); if (r pair SearchR( ll a,int v,ll sl,ll sr,ll d, T prePrd,F carry, IsOK isOK,bool rev )const{ ll l=storedBlockL(sl,d); ll r=storedBlockR(sl,d); if (r pair SearchL( ll b,int v,ll sl,ll sr,ll d, T prePrd,F carry, IsOK isOK,bool rev )const{ ll l=storedBlockL(sl,d); ll r=storedBlockR(sl,d); if (b,…} vll v=dsg.tov(); //長さ 2^B の配列化 - ---- 二分探索 ---- [L,R]内でラムダ式isOKが○(true)になる位置 L,Rは範囲外や逆転も可 未生成の点は e として扱われる - 使用例 ll i=dsg.minRight(L,R,[&](ll x){ return x>=th; }); // L×→×→×ⓡ○R ll i=dsg.maxRight(L,R,[&](ll x){ return x<=th; }); // L○→○→ⓡ××R ll i=dsg.maxLeft (L,R,[&](ll x){ return x>=th; }); //L○ⓛ×←×←×R ll i=dsg.minLeft (L,R,[&](ll x){ return x<=th; }); //L××ⓛ←○←○R - 要件・挙動 minRight: isOK([L,r])=○(L≦r≦R)となる最左のr、ないときR+1 要件:isOK(e)=× maxRight: isOK([L,r])=○(L≦r≦R)となる最右のr、ないときL-1 要件:isOK(e)=○ maxLeft: isOK([l,R])=○(L≦l≦R)となる最右のl、ないときL-1 要件:isOK(e)=× minLeft: isOK([l,R])=○(L≦l≦R)となる最左のl、ないときR+1 要件:isOK(e)=○ */ //pair用テンプレート template inline pair& operator+=(pair &a,const pair &b){ a.first+=b.first; a.second+=b.second; return a; } template inline pair& operator-=(pair &a,const pair &b){ a.first-=b.first; a.second-=b.second; return a; } template inline pair& operator*=(pair &a,const pair &b){ a.first*=b.first; a.second*=b.second; return a; } template inline pair& operator/=(pair &a,const pair &b){ a.first/=b.first; a.second/=b.second; return a; } template inline pair& operator%=(pair &a,const pair &b){ a.first%=b.first; a.second%=b.second; return a; } template inline pair& operator+=(pair &a,R b){ a.first+=b; a.second+=b; return a; } template inline pair& operator-=(pair &a,R b){ a.first-=b; a.second-=b; return a; } template inline pair& operator*=(pair &a,R b){ a.first*=b; a.second*=b; return a; } template inline pair& operator/=(pair &a,R b){ a.first/=b; a.second/=b; return a; } template inline pair& operator%=(pair &a,R b){ a.first%=b; a.second%=b; return a; } template inline pair operator+(const pair &a,R b){ pair c=a; return c+=b; } template inline pair operator-(const pair &a,R b){ pair c=a; return c-=b; } template inline pair operator*(const pair &a,R b){ pair c=a; return c*=b; } template inline pair operator/(const pair &a,R b){ pair c=a; return c/=b; } template inline pair operator%(const pair &a,R b){ pair c=a; return c%=b; } template inline pair operator-(R b,const pair &a){ pair c=-a; return c+=b; } template inline pair operator-(const pair &a,const pair &b){ pair c=a; return c-=b; } template inline pair operator-(const pair &a){ pair c=a; return c*=(-1); } auto solve( ll N,vll A ){ A.push_back(0); /* 現在位置iを左から右へ動かす keyは、左端をi+1としてあり得る右端それぞれの総xor値 valueは、<右端個数c, xor=0にならずたまっている左方の個数s> (1)Ai>総xor値 のとき 1手で0にできる。(1)の範囲のsの総和×1→ans、(1)の範囲のsに0代入 //(2)Ai=総xor値 のとき //0手で0にできる。ansそのまま、(2)の範囲のsに0代入 (3)Ai<総xor値 のとき Ai≧2&A_{i+1}以降続く1の連続数が偶数個のとき→2手 その他→1手 (3)の範囲のsの総和×手数→ans、(3)の範囲のsへの代入なし i→i+1にする準備 空区間を削除:key=0の右端個数cを1減らす 左端を追加:全keyのsにcを足す 総xor値から左端1つ削る:全keyにAi+1をxorする */ vll ren1(N+1);//右方への1の連続数 dep(i,N-1,0){ if (A[i]==1) ren1[i]=ren1[i+1]+1; } using T=pll;//<個数,和> using F=pll;// y=0:z代入,1:z加算 #if defined(_MSC_VER) ll B=4; #else ll B=20; #endif // ┌添字のビット数 // 作用素型F┐ │ ┌データの単位元(実際の単位元でないとだめ) // データ型T┐ ↓ ↓ ↓ ┌作用素の単位元(使わない値ならOK) lazyDynamicSegTree sgt(T(), F(),B,pll(0,0),pll(2,0), [](const T &x,const T &y){ return x+y; }, //op T(T,T) [](const F &f,const T &x,ll l,ll r)->T { auto[c,s]=x; auto[y,z]=f; if (y==0) return {c,c*z}; else return {c,s+c*z}; }, //[l,r]への作用 T(F,T,l,r) [](const F &g,const F &f)->F { auto [y , z]=f; auto [yy,zz]=g; if (yy==0) //後が代入 return {yy,zz}; else return {y,z+zz}; } //作用素合成 F(F,F) fの後gを作用 ); {//左端1の全区間の各総xor値をsgtにセット map mp; ll smx=0; mp[smx]++; rep(i,1,N-1){ smx^=A[i]; mp[smx]++; } for (auto&&[key,ct]:mp){ sgt.set(key,pll(ct,ct)); } } ll ans=0; rep(i,0,N-1){ //for (auto&& e: sgt.tov()) cout << e << '\n'; ll ai=A[i]; //(1)Ai>総xor値 のとき { auto [c,sm]= sgt.get(0,ai-1); ans+=sm*1; sgt.apply(0,ai-1,pll(0,0)); //for (auto&& e: sgt.tov()) cout << e << '\n'; } //(3)Ai<=総xor値 のとき { ll te= (ai>=2 and ren1[i+1]%2==0) ? 2 : 1; auto [c,sm]= sgt.get(ai,INF); ans+=sm*te; } //i→i+1にする準備 {//空区間を削除:key=0の右端個数cを1減らす auto [c,s]=sgt[0]; assert(c>0); if (c>1) sgt.set(0,pll(c-1,s)); else sgt.erase(0); } //左端を追加:全keyのsにcを足す sgt.apply(0,INF,pll(1,1)); //総xor値から左端1つ削る:全keyにAi+1をxorする sgt.xorAllIndex(A[i+1]); } //cout << ans << '\n'; return ans; } auto solve2( ll N,vll A ){ vll Ax=A; Ax.push_front(0); rep(i,1,N) Ax[i]^=Ax[i-1]; auto cmx=[&](ll l,ll r){ return Ax[r+1]^Ax[l]; }; auto ren1=[&](ll i,ll r){ ll ret=0; rep(j,i,r-1){ if (A[j]==1) ret++; else break; } return ret; }; ll ans=0; rep(l,0,N-1) rep(r,l,N-1){ ll sm=0; rep(i,l,r){ ll ai=A[i]; ll cx=cmx(i+1,r); if (ai>cx){ sm++; break; } if (ai==1) sm++; else if (ren1(i+1,r)%2==1) sm++; else sm+=2; } ans+=sm; } return ans; } //#define RANDOM_TEST #if defined(_MSC_VER) #include #endif void solvecomp( ll N,vll A ){ auto coutans=[](auto ans){ cout << ans << '\n'; }; auto ans=solve( N,A ); coutans(ans); #if defined(RANDOM_TEST) cout << "- - - - -\n"; auto an2=solve2( N,A ); coutans(an2); cout << "================\n"; if (ans!=an2){ cout << "============ input =============\n"; cout << N << '\n'; cout << A << '\n'; cout << "============ input end =========\n\n================\n"; #if defined(_MSC_VER) (void)_getch(); #endif } #endif } void cin2solve(){ auto N=cin1(); auto A=cinv(N); solvecomp( N,A ); } namespace RndSpace{ using Int = long long; using dd = long double; struct rndutil{ mt19937 mt; rndutil(Int seed=0):mt(GetSeed(seed)){} Int val(Int a,Int b){ return mt()%(b-a+1)+a; }//[a,b]の乱数 dd dval(){ return (dd)mt()/(1ll<<32); }//[0,1)の浮動小数点乱数 vector ary(Int n,Int a,Int b){//長さnの配列、要素[a,b]内、重複可 vector v(n); for (Int i=0; ival(a,b); return v; } vector
dary(Int n){//長さnの[0,1)の浮動小数点乱数 vector
v(n); for (Int i=0; idval(); return v; } string str(Int n,char cs,char ce){//長さnのstring、使用文字cs~ce、重複可 string str(n,cs); for (Int i=0; ival(0,ce-cs); return str; } vector sample(Int n,Int a,Int b){//長さnの配列、要素[a,b]内、重複無 Int len=b-a+1; assert(n<=len); vector v(len); iota(v.begin(),v.end(),a); for (Int i=0; ival(i,len-1)]); v.resize(n); return v; } template auto sample(const T &v){//1つ選択 return v[val(0,(Int)v.size()-1)]; } template auto samplepop(T &v){//1つ取り出し(末尾swapし削除) Int i=val(0,(Int)v.size()-1); auto ret=v[i]; v[i]=v.back(); v.pop_back(); return ret; } Int weightedSampleCore(const vector &cm){//重み付き乱択 累積和版 Int randval=val(1,cm.back()); return Int(lower_bound(cm.begin(),cm.end(),randval)-cm.begin()); } Int weightedSample(const vector &pr){//重み付き乱択 vector cm=pr; for (Int i=1; i<(Int)cm.size(); ++i) cm[i]+=cm[i-1]; return weightedSampleCore(cm); } template void shuffle(T &v){//配列や文字列をシャッフル Int n=(Int)v.size(); for (Int i=0; ival(i,n-1)]); } pair range(Int a,Int b,Int m=1){ //[a,b]内閉区間長さm以上 while (true){ Int l=this->val(a,b+1),r=this->val(a,b+1); if (r-l> tree(Int N,bool zeroIndexed=false); vector> graph( Int N,Int M,bool isConnected,bool isDirected,bool zeroIndexed=false); vector> wgraph(Int N,Int M,Int cmin,Int cmax, bool isConnected,bool isDirected,bool zeroIndexed=false); template EDGES GraphCore(Int N,Int M,bool isConnected,bool isDirected,bool zeroIndexed); #endif private: unsigned int GetSeed(Int seed){ if (seed>=0) return (unsigned int)seed; return (unsigned int)chrono::system_clock::now().time_since_epoch().count(); } }; }//namespace using RndSpace::rndutil; /* rndutil ru; rndutil ru(-1); //seedランダム(時刻使用) - -------- 整数x -------- 区間[a,b] ll x=ru.val(a,b); - -------- 浮動小数点数x -------- [0,1) dd x=ru.dval(); - -------- 整数ベクトルv -------- 長さn,要素の区間[a,b] 配列重複有 vll v=ru.ary(n,a,b); - -------- 整数ベクトルv -------- 長さn,要素の区間[a,b] 配列重複無 vll v=ru.sample(n,a,b); - -------- 浮動小数点ベクトルv -------- 長さn,[0,1) vdd v=ru.dary(n); - -------- 文字列s -------- 長さn,使用文字'a'~'z' string s=ru.str(n,'a','z'); - -------- 乱択 -------- vll,string等から1つ選択 ll x=ru.sample(v); char c=ru.sample(s); - -------- 乱択削除 -------- vll,string等から1つ取り出し(末尾swapし削除) ll x=ru.samplepop(v); - -------- 重み付き乱択 -------- i∈{0,1,…,n-1}を重みwiで選択 ll i=ru.weightedSample(w); ll i=ru.weightedSampleCore(cm); . ↑wの累積和を与えることで高速に - -------- シャッフル -------- vll,string等 ru.shuffle(a); - -------- 範囲[l,r] -------- [l,r]⊆[a,b] 区間長1以上 auto[l,r]=ru.range(a,b); auto[l,r]=ru.range(a,b,m); . ↑区間長m以上 */ void generand(){ rndutil ru; rep(q,0,INF){ ll N=ru.val(1,4); vll A=ru.ary(N,1,3); //vpll vu=ru.tree(n); solvecomp( N,A ); } } }//SolvingSpace ////////////////////////////////////////// int main(){ #if defined(RANDOM_TEST) SolvingSpace::cin2solve(); SolvingSpace::generand(); #else #if 1 //SolvingSpace::labo();' SolvingSpace::cin2solve(); #else ll t; cin >> t; rep(i,0,t-1){ SolvingSpace::cin2solve(); } #endif #endif cerr << timeget() <<"ms"<< '\n'; return 0; }