#line 1 "verify/graph/tree/mo_on_tree.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/aplusb"
#line 1 "graph/tree/mo_on_tree.hpp"
#include<algorithm>
#include<cassert>
#include<vector>#line 1 "algo/offline/mo.hpp"
#line 6 "algo/offline/mo.hpp"
#include<cmath>
#include<numeric>
#line 9 "algo/offline/mo.hpp"
namespacem1une{namespacealgo{// Offline Mo's algorithm for half-open array ranges.structMo{structQuery{intleft;intright;intid;};private:int_n;std::vector<Query>_queries;public:Mo():_n(0){}explicitMo(intn):_n(n){assert(0<=n);}intsize()const{return_n;}intquery_count()const{returnint(_queries.size());}boolempty()const{return_queries.empty();}conststd::vector<Query>&queries()const{return_queries;}voidreserve(intquery_capacity){assert(0<=query_capacity);_queries.reserve(query_capacity);}voidclear(){_queries.clear();}// Adds [left, right) and returns its insertion-order ID.intadd_query(intleft,intright){assert(0<=left&&left<=right&&right<=_n);intid=query_count();_queries.push_back(Query{left,right,id});returnid;}// Returns query IDs in Mo order. A non-positive block size selects one// automatically.std::vector<int>order(intblock_size=0)const{intquery_size=query_count();std::vector<int>result(query_size);std::iota(result.begin(),result.end(),0);if(query_size==0)returnresult;if(block_size<=0){block_size=std::max(1,int(_n/std::sqrt(static_cast<double>(query_size))));}std::sort(result.begin(),result.end(),[&](intfirst,intsecond){constQuery&a=_queries[first];constQuery&b=_queries[second];intfirst_block=a.left/block_size;intsecond_block=b.left/block_size;if(first_block!=second_block){returnfirst_block<second_block;}if(first_block&1)returna.right>b.right;returna.right<b.right;});returnresult;}// Maintains [left, right). Each movement callback receives the array index// being inserted or erased. `answer(query_id)` stores or reports a result.template<classAddLeft,classAddRight,classRemoveLeft,classRemoveRight,classAnswer>voidrun(AddLeftadd_left,AddRightadd_right,RemoveLeftremove_left,RemoveRightremove_right,Answeranswer,intblock_size=0)const{intleft=0;intright=0;for(intquery_index:order(block_size)){constQuery&query=_queries[query_index];while(query.left<left)add_left(--left);while(right<query.right)add_right(right++);while(left<query.left)remove_left(left++);while(query.right<right)remove_right(--right);answer(query.id);}}// Convenience overload for statistics whose update is independent of// which side moves.template<classAdd,classRemove,classAnswer>voidrun(Addadd,Removeremove,Answeranswer,intblock_size=0)const{run(add,add,remove,remove,answer,block_size);}};}// namespace algo}// namespace m1une#line 1 "graph/graph.hpp"
#include<array>
#line 6 "graph/graph.hpp"
#include<utility>
#line 8 "graph/graph.hpp"
namespacem1une{namespacegraph{template<classT=int>structEdge{usingcost_type=T;intfrom;intto;Tcost;intid;boolalive;Edge():from(-1),to(-1),cost(T()),id(-1),alive(true){}Edge(intfrom_,intto_,Tcost_=T(1),intid_=-1,boolalive_=true):from(from_),to(to_),cost(cost_),id(id_),alive(alive_){}intother(intv)const{assert(v==from||v==to);returnfrom^to^v;}};template<classT=int>structGraph{usingedge_type=Edge<T>;usingcost_type=T;private:structEdgePositions{std::array<std::pair<int,int>,2>value{};intsize=0;voidpush_back(std::pair<int,int>position){assert(size<2);value[size++]=position;}};int_n;int_edge_count;std::vector<std::vector<edge_type>>_g;std::vector<EdgePositions>_edge_positions;public:Graph():_n(0),_edge_count(0){}explicitGraph(intn):_n(n),_edge_count(0),_g(n){assert(0<=n);}intsize()const{return_n;}boolempty()const{return_n==0;}intedge_count()const{return_edge_count;}intadd_vertex(){_g.emplace_back();return_n++;}intadd_directed_edge(intfrom,intto,Tcost=T(1)){assert(0<=from&&from<_n);assert(0<=to&&to<_n);intid=_edge_count++;intidx=int(_g[from].size());_g[from].push_back(edge_type(from,to,cost,id));_edge_positions.emplace_back();_edge_positions.back().push_back({from,idx});returnid;}intadd_edge(intu,intv,Tcost=T(1)){assert(0<=u&&u<_n);assert(0<=v&&v<_n);intid=_edge_count++;intu_idx=int(_g[u].size());_g[u].push_back(edge_type(u,v,cost,id));intv_idx=int(_g[v].size());_g[v].push_back(edge_type(v,u,cost,id));_edge_positions.emplace_back();_edge_positions.back().push_back({u,u_idx});_edge_positions.back().push_back({v,v_idx});returnid;}voidset_edge_alive(intid,boolalive){assert(0<=id&&id<_edge_count);for(inti=0;i<_edge_positions[id].size;++i){auto[v,idx]=_edge_positions[id].value[i];_g[v][idx].alive=alive;}}voiderase_edge(intid){set_edge_alive(id,false);}voidrevive_edge(intid){set_edge_alive(id,true);}boolis_edge_alive(intid)const{assert(0<=id&&id<_edge_count);assert(_edge_positions[id].size!=0);auto[v,idx]=_edge_positions[id].value[0];return_g[v][idx].alive;}conststd::vector<edge_type>&operator[](intv)const{assert(0<=v&&v<_n);return_g[v];}std::vector<edge_type>&operator[](intv){assert(0<=v&&v<_n);return_g[v];}conststd::vector<std::vector<edge_type>>&adjacency()const{return_g;}std::vector<std::vector<edge_type>>&adjacency(){return_g;}std::vector<edge_type>edges(boolinclude_inactive=false)const{std::vector<edge_type>result;result.reserve(_edge_count);std::vector<char>used(_edge_count,false);for(intv=0;v<_n;v++){for(constauto&e:_g[v]){if(!include_inactive&&!e.alive)continue;if(0<=e.id&&e.id<_edge_count){if(used[e.id])continue;used[e.id]=true;}result.push_back(e);}}returnresult;}Graphreversed()const{Graphresult(_n);result._edge_count=_edge_count;result._edge_positions.assign(_edge_count,{});for(intv=0;v<_n;v++){for(constauto&e:_g[v]){intidx=int(result._g[e.to].size());result._g[e.to].push_back(edge_type(e.to,e.from,e.cost,e.id,e.alive));if(0<=e.id&&e.id<_edge_count)result._edge_positions[e.id].push_back({e.to,idx});}}returnresult;}};}// namespace graph}// namespace m1une#line 1 "graph/tree/heavy_light_decomposition.hpp"
#line 8 "graph/tree/heavy_light_decomposition.hpp"
#line 10 "graph/tree/heavy_light_decomposition.hpp"
namespacem1une{namespacetree{structHldPathSegment{intl;intr;boolreversed;};template<classT=int>structHeavyLightDecomposition{usingcost_type=T;usingedge_type=m1une::graph::Edge<T>;introot;std::vector<int>parent;std::vector<int>parent_edge;std::vector<int>depth;std::vector<T>dist;std::vector<int>subtree_size;std::vector<int>heavy;std::vector<int>head;std::vector<int>tin;std::vector<int>tout;std::vector<int>order;private:int_n;voidcheck_vertex(intv)const{assert(0<=v&&v<_n);assert(tin[v]!=-1);}staticvoidadd_segment(std::vector<HldPathSegment>&result,intl,intr,boolreversed){if(l<r)result.push_back({l,r,reversed});}public:HeavyLightDecomposition():root(-1),_n(0){}explicitHeavyLightDecomposition(constm1une::graph::Graph<T>&g,introot_=0){build(g,root_);}voidbuild(constm1une::graph::Graph<T>&g,introot_=0){_n=g.size();root=_n==0?-1:root_;parent.assign(_n,-2);parent_edge.assign(_n,-1);depth.assign(_n,0);dist.assign(_n,T(0));subtree_size.assign(_n,1);heavy.assign(_n,-1);head.assign(_n,-1);tin.assign(_n,-1);tout.assign(_n,-1);order.clear();order.reserve(_n);if(_n==0)return;assert(0<=root&&root<_n);std::vector<int>dfs_order;dfs_order.reserve(_n);std::vector<int>stack={root};parent[root]=-1;while(!stack.empty()){intv=stack.back();stack.pop_back();dfs_order.push_back(v);for(constauto&e:g[v]){if(!e.alive)continue;if(parent[e.to]!=-2)continue;parent[e.to]=v;parent_edge[e.to]=e.id;depth[e.to]=depth[v]+1;dist[e.to]=dist[v]+e.cost;stack.push_back(e.to);}}for(inti=int(dfs_order.size())-1;i>=0;i--){intv=dfs_order[i];if(parent[v]==-1)continue;intp=parent[v];subtree_size[p]+=subtree_size[v];if(heavy[p]==-1||subtree_size[heavy[p]]<subtree_size[v])heavy[p]=v;}order.assign(dfs_order.size(),-1);inttimer=0;std::vector<std::pair<int,int>>starts={std::pair<int,int>{root,root}};while(!starts.empty()){auto[start,h]=starts.back();starts.pop_back();for(intv=start;v!=-1;v=heavy[v]){head[v]=h;tin[v]=timer;order[timer++]=v;for(autoit=g[v].rbegin();it!=g[v].rend();++it){if(!it->alive)continue;intto=it->to;if(parent[to]!=v||to==heavy[v])continue;starts.push_back({to,to});}}}for(inti=int(dfs_order.size())-1;i>=0;i--){intv=dfs_order[i];tout[v]=tin[v]+subtree_size[v];}}intsize()const{return_n;}boolempty()const{return_n==0;}boolis_ancestor(intu,intv)const{check_vertex(u);check_vertex(v);returntin[u]<=tin[v]&&tout[v]<=tout[u];}intlca(intu,intv)const{check_vertex(u);check_vertex(v);while(head[u]!=head[v]){if(depth[head[u]]<depth[head[v]])std::swap(u,v);u=parent[head[u]];}returndepth[u]<depth[v]?u:v;}intdist_edges(intu,intv)const{intw=lca(u,v);returndepth[u]+depth[v]-2*depth[w];}Tdist_cost(intu,intv)const{intw=lca(u,v);returndist[u]+dist[v]-dist[w]-dist[w];}intkth_ancestor(intv,intk)const{check_vertex(v);assert(0<=k);while(v!=-1){inth=head[v];intlen=depth[v]-depth[h];if(k<=len)returnorder[tin[v]-k];k-=len+1;v=parent[h];}return-1;}intjump(intfrom,intto,intk)const{check_vertex(from);check_vertex(to);assert(0<=k);intw=lca(from,to);intup_len=depth[from]-depth[w];intdown_len=depth[to]-depth[w];if(up_len+down_len<k)return-1;if(k<=up_len)returnkth_ancestor(from,k);returnkth_ancestor(to,down_len-(k-up_len));}std::pair<int,int>subtree_range(intv,booledge=false)const{check_vertex(v);return{tin[v]+(edge?1:0),tout[v]};}std::vector<HldPathSegment>path_segments(intu,intv,booledge=false)const{check_vertex(u);check_vertex(v);std::vector<HldPathSegment>result,down;while(head[u]!=head[v]){if(depth[head[u]]>=depth[head[v]]){add_segment(result,tin[head[u]],tin[u]+1,true);u=parent[head[u]];}else{add_segment(down,tin[head[v]],tin[v]+1,false);v=parent[head[v]];}}if(depth[u]>=depth[v]){add_segment(result,tin[v]+(edge?1:0),tin[u]+1,true);}else{add_segment(down,tin[u]+(edge?1:0),tin[v]+1,false);}std::reverse(down.begin(),down.end());result.insert(result.end(),down.begin(),down.end());returnresult;}template<classF>voidfor_each_path(intu,intv,Ff,booledge=false)const{for(autoseg:path_segments(u,v,edge))f(seg.l,seg.r,seg.reversed);}};}// namespace tree}// namespace m1une#line 11 "graph/tree/mo_on_tree.hpp"
namespacem1une{namespacetree{// Offline Mo's algorithm for static paths in a tree.template<classT=int>structMoOnTree{structQuery{intfrom;intto;intleft;intright;intextra;intid;booledge;};introot;std::vector<int>entry;std::vector<int>exit;std::vector<int>tour;private:int_n;HeavyLightDecomposition<T>_hld;m1une::algo::Mo_mo;std::vector<Query>_queries;voidcheck_vertex(intvertex)const{assert(0<=vertex&&vertex<_n);assert(entry[vertex]!=-1);}intadd_path_query(intfrom,intto,booledge){check_vertex(from);check_vertex(to);assert(_queries.empty()||_queries.front().edge==edge);intoriginal_from=from;intoriginal_to=to;if(entry[from]>entry[to])std::swap(from,to);intancestor=_hld.lca(from,to);intleft;intright=entry[to]+1;intextra=-1;if(ancestor==from){left=entry[from]+int(edge);}else{left=exit[from];if(!edge)extra=ancestor;}intid=_mo.add_query(left,right);_queries.push_back(Query{original_from,original_to,left,right,extra,id,edge,});returnid;}public:MoOnTree():root(-1),_n(0),_mo(0){}explicitMoOnTree(constm1une::graph::Graph<T>&graph,introot_vertex=0):root(-1),_n(0),_mo(0){build(graph,root_vertex);}voidbuild(constm1une::graph::Graph<T>&graph,introot_vertex=0){_n=graph.size();root=_n==0?-1:root_vertex;entry.assign(_n,-1);exit.assign(_n,-1);tour.clear();tour.reserve(2*_n);_queries.clear();_mo=m1une::algo::Mo(2*_n);_hld.build(graph,root_vertex);if(_n==0)return;assert(0<=root&&root<_n);for(intvertex=0;vertex<_n;++vertex){assert(_hld.parent[vertex]!=-2);}std::vector<std::vector<int>>children(_n);for(intvertex=0;vertex<_n;++vertex){intparent=_hld.parent[vertex];if(parent!=-1)children[parent].push_back(vertex);}structEvent{intvertex;boolleaving;};std::vector<Event>stack;stack.reserve(2*_n);stack.push_back(Event{root,false});while(!stack.empty()){Eventevent=stack.back();stack.pop_back();intvertex=event.vertex;if(event.leaving){exit[vertex]=int(tour.size());tour.push_back(vertex);continue;}entry[vertex]=int(tour.size());tour.push_back(vertex);stack.push_back(Event{vertex,true});constauto&child_list=children[vertex];for(intindex=int(child_list.size())-1;index>=0;--index){stack.push_back(Event{child_list[index],false});}}assert(int(tour.size())==2*_n);}intsize()const{return_n;}boolempty()const{return_n==0;}intquery_count()const{returnint(_queries.size());}conststd::vector<Query>&queries()const{return_queries;}intparent(intvertex)const{check_vertex(vertex);return_hld.parent[vertex];}intparent_edge(intvertex)const{check_vertex(vertex);return_hld.parent_edge[vertex];}intdepth(intvertex)const{check_vertex(vertex);return_hld.depth[vertex];}intlca(intfirst,intsecond)const{check_vertex(first);check_vertex(second);return_hld.lca(first,second);}voidreserve(intquery_capacity){assert(0<=query_capacity);_queries.reserve(query_capacity);_mo.reserve(query_capacity);}voidclear(){_queries.clear();_mo.clear();}// Adds an inclusive vertex-path query and returns its insertion-order ID.// Vertex and edge queries cannot be mixed in one collection.intadd_query(intfrom,intto){returnadd_path_query(from,to,false);}// Adds an edge-path query. Each edge is represented by its child vertex.intadd_edge_query(intfrom,intto){returnadd_path_query(from,to,true);}std::vector<int>order(intblock_size=0)const{return_mo.order(block_size);}// `add(v)` and `remove(v)` maintain the current path. In edge mode, v// always represents the real edge parent_edge(v).template<classAdd,classRemove,classAnswer>voidrun(Addadd,Removeremove,Answeranswer,intblock_size=0)const{booledge_mode=!_queries.empty()&&_queries.front().edge;std::vector<char>active(_n,false);autotoggle=[&](inttour_index){intvertex=tour[tour_index];if(!edge_mode||vertex!=root){if(active[vertex]){remove(vertex);}else{add(vertex);}}active[vertex]=!active[vertex];};_mo.run(toggle,toggle,[&](intquery_id){intextra=_queries[query_id].extra;if(extra!=-1){assert(!active[extra]);add(extra);}answer(query_id);if(extra!=-1)remove(extra);},block_size);}};}// namespace tree}// namespace m1une#line 4 "verify/graph/tree/mo_on_tree.test.cpp"
#line 7 "verify/graph/tree/mo_on_tree.test.cpp"
#include<cstdint>
#include<iostream>
#include<queue>
#line 12 "verify/graph/tree/mo_on_tree.test.cpp"
namespace{structPath{std::vector<int>vertices;std::vector<int>edges;};Pathnaive_path(conststd::vector<std::vector<std::pair<int,int>>>&adjacency,intfrom,intto){intn=int(adjacency.size());std::vector<int>previous(n,-1);std::vector<int>previous_edge(n,-1);std::queue<int>queue;previous[from]=from;queue.push(from);while(!queue.empty()){intvertex=queue.front();queue.pop();for(auto[next,edge_id]:adjacency[vertex]){if(previous[next]!=-1)continue;previous[next]=vertex;previous_edge[next]=edge_id;queue.push(next);}}Pathresult;for(intvertex=to;vertex!=from;vertex=previous[vertex]){result.vertices.push_back(vertex);result.edges.push_back(previous_edge[vertex]);}result.vertices.push_back(from);std::reverse(result.vertices.begin(),result.vertices.end());std::reverse(result.edges.begin(),result.edges.end());returnresult;}voidtest_empty_tree(){m1une::graph::Graph<int>graph;m1une::tree::MoOnTree<int>mo;mo.build(graph);assert(mo.empty());assert(mo.size()==0);assert(mo.query_count()==0);assert(mo.order().empty());mo.run([](int){assert(false);},[](int){assert(false);},[](int){assert(false);});}voidtest_deep_path(){constexprintn=200000;m1une::graph::Graph<int>graph(n);for(intvertex=1;vertex<n;++vertex){graph.add_edge(vertex-1,vertex);}m1une::tree::MoOnTree<int>mo(graph,n-1);mo.add_query(0,n-1);mo.add_query(12345,67890);mo.add_query(77777,77777);std::vector<int>answer(3);intcount=0;mo.run([&](int){count++;},[&](int){count--;},[&](intquery){answer[query]=count;});assert(answer[0]==n);assert(answer[1]==67890-12345+1);assert(answer[2]==1);}voidtest_randomized(){std::uint64_tstate=0x3141592653589793ULL;autorandom=[&](){state^=state<<7;state^=state>>9;returnstate;};for(inttrial=0;trial<1500;++trial){intn=1+int(random()%55);intquery_count=int(random()%85);m1une::graph::Graph<int>graph(n);std::vector<std::vector<std::pair<int,int>>>adjacency(n);std::vector<longlong>edge_weight(std::max(0,n-1));for(intvertex=1;vertex<n;++vertex){intparent=int(random()%vertex);intedge_id=graph.add_edge(parent,vertex);adjacency[parent].push_back({vertex,edge_id});adjacency[vertex].push_back({parent,edge_id});edge_weight[edge_id]=int(random()%101)-50;}std::vector<int>color(n);std::vector<longlong>weight(n);for(intvertex=0;vertex<n;++vertex){color[vertex]=int(random()%13);weight[vertex]=int(random()%101)-50;}introot=int(random()%n);m1une::tree::MoOnTree<int>vertex_mo(graph,root);assert(vertex_mo.size()==n);assert(vertex_mo.root==root);assert(int(vertex_mo.tour.size())==2*n);std::vector<int>occurrence(n);for(intvertex:vertex_mo.tour)occurrence[vertex]++;for(intvertex=0;vertex<n;++vertex){assert(occurrence[vertex]==2);assert(vertex_mo.tour[vertex_mo.entry[vertex]]==vertex);assert(vertex_mo.tour[vertex_mo.exit[vertex]]==vertex);assert(vertex_mo.entry[vertex]<vertex_mo.exit[vertex]);}vertex_mo.reserve(query_count);std::vector<Path>paths;paths.reserve(query_count);for(intquery=0;query<query_count;++query){intfrom=int(random()%n);intto=int(random()%n);assert(vertex_mo.add_query(from,to)==query);paths.push_back(naive_path(adjacency,from,to));constauto&stored=vertex_mo.queries().back();assert(stored.id==query);assert(stored.from==from&&stored.to==to);assert(!stored.edge);}std::vector<int>order=vertex_mo.order();std::sort(order.begin(),order.end());for(intquery=0;query<query_count;++query){assert(order[query]==query);}std::vector<int>frequency(13);std::vector<longlong>answer_sum(query_count);std::vector<int>answer_distinct(query_count);longlongsum=0;intdistinct=0;vertex_mo.run([&](intvertex){sum+=weight[vertex];if(frequency[color[vertex]]++==0)distinct++;},[&](intvertex){sum-=weight[vertex];if(--frequency[color[vertex]]==0)distinct--;},[&](intquery){answer_sum[query]=sum;answer_distinct[query]=distinct;},trial%3==0?1+int(random()%(2*n)):0);for(intquery=0;query<query_count;++query){longlongexpected_sum=0;std::vector<char>seen(13,false);intexpected_distinct=0;for(intvertex:paths[query].vertices){expected_sum+=weight[vertex];if(!seen[color[vertex]]){seen[color[vertex]]=true;expected_distinct++;}}assert(answer_sum[query]==expected_sum);assert(answer_distinct[query]==expected_distinct);}m1une::tree::MoOnTree<int>edge_mo(graph,root);edge_mo.reserve(query_count);for(intquery=0;query<query_count;++query){intfrom=paths[query].vertices.front();intto=paths[query].vertices.back();assert(edge_mo.add_edge_query(from,to)==query);assert(edge_mo.queries().back().edge);}std::vector<longlong>edge_answer(query_count);longlongedge_sum=0;edge_mo.run([&](intchild){intedge_id=edge_mo.parent_edge(child);assert(edge_id!=-1);edge_sum+=edge_weight[edge_id];},[&](intchild){intedge_id=edge_mo.parent_edge(child);assert(edge_id!=-1);edge_sum-=edge_weight[edge_id];},[&](intquery){edge_answer[query]=edge_sum;});for(intquery=0;query<query_count;++query){longlongexpected=0;for(intedge_id:paths[query].edges){expected+=edge_weight[edge_id];}assert(edge_answer[query]==expected);}vertex_mo.clear();assert(vertex_mo.query_count()==0);assert(vertex_mo.order().empty());}}}// namespaceintmain(){test_empty_tree();test_deep_path();test_randomized();longlongfirst,second;std::cin>>first>>second;std::cout<<first+second<<'\n';}