#include "../template/includes.cpp"
template<typenameDataStructure>structHeavyLightDecomposition{usingvalue_type=typenameDataStructure::value_type;usingupdate_type=typenameDataStructure::update_type;usingMonoid=typenameDataStructure::Monoid;structChain{intdepth;std::pair<int,int>parent;// chain number, indexstd::vector<std::pair<int,int>>child;// child chain number, parent indexstd::vector<int>mapfrom;DataStructureup,down;Chain(intn,constvalue_type&init):up(n,init),down(n,init){;}};std::vector<Chain>chains;std::vector<std::pair<int,int>>mapto;// raw index -> chain number & indexstd::vector<std::vector<int>>mapfrom;// chain number & index -> raw indexintroot()const{returnmapfrom[0][0];}template<typenameGraph>HeavyLightDecomposition(constGraph&g,constvalue_type&init=Monoid::id()){constintn=g.size();mapto=std::vector<std::pair<int,int>>(n,std::make_pair(-1,-1));mapfrom.clear();std::vector<int>size(n,0);intstart=-1;for(inti=0;i<n;i++){if(g[i].size()<=1){start=i;break;}}assert(start!=-1);size_check_bfs(g,start,size);decomposition(g,start,start,0,0,0,size,init);}voidupdate(inti,constupdate_type&val){conststd::pair<int,int>chain_id=mapto[i];constintn=chains[chain_id.first].mapfrom.size();chains[chain_id.first].up.update(n-i-1,val);chains[chain_id.first].down.update(i,val);}voidupdate(ints,intt,constupdate_type&update){std::pair<int,int>chain_s=mapto[s],chain_t=mapto[t];while(chain_s.first!=chain_t.first){if(chains[chain_s.first].depth>chains[chain_t.first].depth){constintnum=chain_s.second+1;constintn=chains[chain_s.first].mapfrom.size();chains[chain_s.first].up.update(n-num,n,update);chains[chain_s.first].down.update(0,num,update);chain_s=chains[chain_s.first].parent;}else{constintnum=chain_t.second+1;constintn=chains[chain_t.first].mapfrom.size();chains[chain_t.first].up.update(n-num,n,update);chains[chain_t.first].down.update(0,num,update);chain_t=chains[chain_t.first].parent;}}constintn=chains[chain_s.first].mapfrom.size();constintl=std::min(chain_s.second,chain_t.second);constintr=std::max(chain_s.second,chain_t.second);chains[chain_s.first].up.update(n-r-1,n-l,update);chains[chain_s.first].down.update(l,r+1,update);}value_typequery(ints,intt){value_typeres1=Monoid::id(),res2=Monoid::id();std::pair<int,int>chain_s=mapto[s],chain_t=mapto[t];while(chain_s.first!=chain_t.first){if(chains[chain_s.first].depth>chains[chain_t.first].depth){constintnum=chain_s.second+1;constintn=chains[chain_s.first].mapfrom.size();constvalue_typeval=chains[chain_s.first].up.query(n-num,n);res1=Monoid::op(res1,val);chain_s=chains[chain_s.first].parent;}else{constintnum=chain_t.second+1;constvalue_typeval=chains[chain_t.first].down.query(0,num);res2=Monoid::op(val,res2);chain_t=chains[chain_t.first].parent;}}constintn=chains[chain_s.first].mapfrom.size();constintl=chain_s.second;constintr=chain_t.second;constvalue_typeval=l>r?chains[chain_s.first].up.query(n-l-1,n-r):chains[chain_s.first].down.query(l,r+1);returnMonoid::op(Monoid::op(res1,val),res2);}intdepth(intt)const{returnchains[mapto[t].first].depth;}private:template<typenameGraph>intdecomposition(Graph&g,intfrom,intparent,intdepth,intpnumber,intpindex,conststd::vector<int>&size,constvalue_type&init){std::vector<int>seq;bfs(g,from,parent,seq,size);constintc=chains.size();chains.push_back(Chain(int(seq.size()),init));chains[c].depth=depth;chains[c].parent=std::make_pair(pnumber,pindex);for(inti=0;i<int(seq.size());i++){mapto[seq[i]]=std::make_pair(c,i);chains[c].mapfrom.push_back(seq[i]);}mapfrom.push_back(chains[c].mapfrom);for(inti=0;i<int(seq.size());i++){for(autoe:g[seq[i]]){if(mapto[e.to].first!=-1)continue;constintnc=decomposition(g,e.to,seq[i],depth+1,c,i,size,init);chains[c].child.push_back(std::make_pair(nc,i));}}returnc;}template<typenameGraph>voidsize_check_bfs(constGraph&g,intstart,std::vector<int>&size){constintn=g.size();std::queue<std::pair<int,int>>que;que.push(std::make_pair(start,start));intcnt=0;std::vector<int>order(n,-1);while(!que.empty()){intfrom,parent;std::tie(from,parent)=que.front();que.pop();order[cnt++]=from;for(autoe:g[from]){if(e.to==parent)continue;que.push(std::make_pair(e.to,from));}}assert(cnt==n);reverse(begin(order),end(order));for(inti=0;i<n;i++){constintfrom=order[i];size[from]=1;for(autoe:g[from])size[from]+=size[e.to];}}template<typenameGraph>voidbfs(constGraph&g,intfrom,intparent,std::vector<int>&seq,conststd::vector<int>&size){for(;;){seq.push_back(from);intbest=-1,next=-1;for(autoe:g[from]){if(e.to==parent)continue;if(best<size[e.to]){best=size[e.to];next=e.to;}}if(next==-1)break;parent=from;from=next;}}};