还没打完数学专题呢就来打这个了。(其实是不会多项式)
难度大概升序。
Giving Awards
注意到一个关键信息:每对人只会被提到一次。所以一定有解。
考虑卡bug,假如\(a\)欠\(b\)钱,那么就先让\(b\)取钱再让\(a\)取钱,建边dfs即可,注意图不连通。
点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCALauto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#elseauto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
const int N = 3e4 + 10;
#define eb emplace_back
vector<int> e[N],ans;
bitset<N> vis;
int n,m,d[N];
void dfs(int x,int fa){vis[x] = true;for(auto y:e[x]){if(vis[y]) continue;dfs(y,x);}ans.emplace_back(x);
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);cin>>n>>m;rep(i,1,m,1){int x,y;cin>>x>>y;e[x].eb(y);}rep(i,1,n,1) if(!vis[i]) dfs(i,0);for(auto i:ans) cout<<i<<' ';
}
[BJWC2010] 严格次小生成树
一个结论:次小生成树与最小生成树只会有一条边不同。
先将最小生成树求出来,然后考虑所有的非树边,发现这条边\((u,v,w)\)替换的必定是\(u\rightarrow LCA(u,v),v\rightarrow LCA(u,v)\)上的一条边\((u^\prime,v^\prime,w^\prime),w^\prime < w\)。
那么现在就是求\(u\rightarrow v\)的简单路径上所有的边中,\(w\)的前驱。
不会倍增,只会树剖+线段树,考虑将所有树边排序,每次查询非树边时,将所有权值小于它的假如,然后求链上最大值即可,但是边权不好做,考虑边权转点权即可,时间复杂度\(O(m\log^2 n)\),但是由于树剖常数小,跑的和倍增差不多,而且空间比倍增优秀。
点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCALauto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#elseauto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
#define eb emplace_back
const int N = 1e5 + 10,M = 3e5 + 10;
vector<pair<int,int> > e[N];
int n,m;struct node{int x,y,z;}edge[M];
bitset<M> unused;
int dist[N],top[N],siz[N],son[N],dfn[N],rdfn[N],tim,dep[N],fa[N];
struct DSU{vector<int> fa;void init(int n){fa.resize(n+1);rep(i,1,n,1) fa[i] = i;}int get_fa(int x){while(x ^ fa[x]) x = fa[x] = fa[fa[x]];return x;}bool Merge(int x,int y){x = get_fa(x),y = get_fa(y);if(x == y) return false;return fa[x] = y,true;}
}D;
struct Segment_Tree{struct segment_tree{int l,r,val;#define l(x) tree[x].l#define r(x) tree[x].r#define val(x) tree[x].val}tree[N<<2];void B(int k = 1,int l = 1,int r = n){l(k) = l,r(k) = r;if(l == r) return;int mid = (l + r) >> 1;B(k<<1,l,mid);B(k<<1|1,mid+1,r);}void upd(int k,int pos,int val){if(l(k) == r(k)) return val(k) = val,void();int mid = (l(k) + r(k)) >> 1;pos <= mid?upd(k<<1,pos,val):upd(k<<1|1,pos,val);val(k) = max(val(k<<1),val(k<<1|1));}int qry(int k,int l,int r){if(l <= l(k) && r(k) <= r) return val(k);int mid = (l(k) + r(k)) >> 1,res = 0;if(l <= mid) res = max(res,qry(k<<1,l,r));if(r > mid) res = max(res,qry(k<<1|1,l,r));return res;}
}T;
void dfs1(int x){siz[x] = 1,dep[x] = dep[fa[x]] + 1;for(auto [y,w]:e[x]){if(y == fa[x]) continue;fa[y] = x;dfs1(y);dist[y] = w;siz[x] += siz[y];if(siz[son[x]] < siz[y]) son[x] = y;}
}
void dfs2(int x,int t){top[x] = t;rdfn[dfn[x] = ++tim] = x;if(son[x]) dfs2(son[x],t);else return;for(auto [y,w]:e[x]){if(y == fa[x] || y == son[x]) continue;dfs2(y,y);}
}
int query(int x,int y){int fx = top[x],fy = top[y];int res = 0;while(fx ^ fy){if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy);res = max(res,T.qry(1,dfn[fx],dfn[x]));x = fa[fx];fx = top[x];}if(dep[x] > dep[y]) swap(x,y);if(x == y) return res;res = max(res,T.qry(1,dfn[x]+1,dfn[y]));return res;
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);cin>>n>>m;rep(i,1,m,1) cin>>edge[i].x>>edge[i].y>>edge[i].z;D.init(n);sort(edge+1,edge+1+m,[](node x,node y){return x.z < y.z;});ll total = 0;rep(i,1,m,1){auto [x,y,w] = edge[i];auto flag = D.Merge(x,y);if(!flag){unused[i] = true;continue;}e[x].eb(y,w);e[y].eb(x,w);total += w;}dfs1(1);dfs2(1,1);T.B();int ans = 1e9;int now = 1;rep(i,1,m,1){auto [x,y,w] = edge[i];while(now <= m && edge[now].z < w){if(unused[now]){now++;continue;}auto [x,y,w] = edge[now];if(fa[x] == y) T.upd(1,dfn[x],edge[now].z);if(fa[y] == x) T.upd(1,dfn[y],edge[now].z);now++;}if(!unused[i]) continue;if(x == y) continue;int res = w-query(x,y);ans = min(ans,res);}cout<<total + ans<<'\n';
}
跳楼机
同余最短路板子,当个学习笔记写。
当出现形如
- 给定 \(n\) 个整数,求这 \(n\) 个整数能拼凑出多少的其他整数 (\(n\) 个整数可以重复取)。
- 给定 \(n\) 个整数,求这 \(n\) 个整数不能拼凑出的最小(最大)的整数。
- 至少要拼几次才能拼出模 \(K\) 余 \(p\) 的数
等问题时可以使用同余最短路的方法。
既然带了最短路,那么就类比最短路。同余最短路中的转移通常是\(f(i+y)=f(i)+y\),类比\(dist_v=dist_u+e(u,v)\)。
考虑这道题,设\(d_i\)表示只通过\(2,3\)操作,满足\(p\bmod x=i\)的最小的\(p\),那么就有\(f((i+y)\bmod x)=f(i)+y,f((i+z)\bmod x)=f(i)+z\)。实质上就是最短路中的加边操作,接下来只需要求出\(d_0,d_1,\ldots,d_{x-1}\)即可,答案为\(\sum\limits_{i=0}^{x-1}[h\ge d_i](\frac{h-d_i}{x}+1)\)。但是由于本题\(h\le 2^{63}-1\),求解时\(d\)的初值至少应为\(2^63>LLONG\_MAX\),所以可以将\(h\leftarrow h-1\),将初始楼层设为\(0\)即可。
点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCALauto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#elseauto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
#define int ull
const int N = 1e5 + 10;
int h,x,y,z,dist[N];
vector<pair<int,int> > e[N];
bitset<N> vis;
void dijkstra(){memset(dist,0x3f,sizeof dist);priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;q.emplace(0,0);dist[0] = 0;while(q.size()){int x = q.top().second;q.pop();if(vis[x]) continue;vis[x] = true;for(auto [y,w]:e[x]){if(dist[y] > dist[x] + w){dist[y] = dist[x] + w;q.emplace(dist[y],y);}}}
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);cin>>h>>x>>y>>z;h--;rep(i,0,x-1,1){e[i].emplace_back((i+y)%x,y);e[i].emplace_back((i+z)%x,z);}dijkstra();int ans = 0;rep(i,0,x-1,1) if(h >= dist[i]) ans += (h-dist[i])/x+1;cout<<ans<<'\n';
}
[国家集训队] 墨墨的等式
显然答案具有可差分性,考虑求出\([0,l),[0,r]\)中的可以凑出的值作差即可,处理方法同上。
点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCALauto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#elseauto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
const int N = 5e5 + 10;
int n,x;bitset<N> vis;
vector<pair<int,int> > e[N];
ll l,r,dist[N];
vector<int> num;
void dijkstra(int s){memset(dist,0x3f,sizeof dist);priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q;q.emplace(0,0);dist[0] = 0;while(q.size()){int x = q.top().second;q.pop();if(vis[x]) continue;vis[x] = true;for(auto [y,w]:e[x]){if(dist[y] > dist[x] + w){dist[y] = dist[x] + w;q.emplace(dist[y],y);}}}
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);cin>>n>>l>>r>>x;l--;rep(i,2,n,1){int x;cin>>x;num.emplace_back(x);}rep(i,0,x-1,1) for(auto j:num) e[i].emplace_back((i+j)%x,j);dijkstra(0);ll ans = 0;rep(i,0,x-1,1) if(l >= dist[i]) ans -= (l-dist[i])/x+1;rep(i,0,x-1,1) if(r >= dist[i]) ans += (r-dist[i])/x+1;cout<<ans<<'\n';
}
Fairy
【模板】线段树分治
线段树分治太naive了,考虑换个优秀的做法。
显然答案为奇环交,考虑如何求这个。考虑跑一遍dfs,求出一颗生成树。
对于一条非树边,显然会形成一个环,称这个环上的树边被其覆盖。
如果一条非树边和树边形成一个有且仅有这一条非树边的奇环,那么称这条非树边为坏边。
显然答案边被所有坏边覆盖,且不被好边覆盖。
然后直接树上差分就可以了,时间复杂度\(O(n)\)。
点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCALauto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#elseauto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
const int N = 1e4 + 10;
#define eb emplace_back
vector<int> e[N],id[N],ans;
bitset<N> vis;
bool dis[N],ok[N];
int s[N],ct,eid,n,m;
void dfs(int x){vis[x] = true;rep(i,0,(int)e[x].size()-1,1){int y = e[x][i];if(!vis[y]){dis[y] = dis[x]^1;ok[id[x][i]] = 1;dfs(y);}else if(!ok[id[x][i]]){ok[id[x][i]] = 1;if(dis[y] == dis[x]){ct++;s[x]++;s[y]--;eid = id[x][i];}else s[x]--,s[y]++;}}
}
void dfs1(int x){vis[x] = true;rep(i,0,(int)e[x].size() - 1,1){int y = e[x][i];if(!vis[y]){dfs1(y);if(s[y] == ct) ans.emplace_back(id[x][i]);s[x] += s[y];}}
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);cin>>n>>m;rep(i,1,m,1){int u,v;cin>>u>>v;e[u].eb(v);e[v].eb(u);id[u].eb(i);id[v].eb(i);}rep(i,1,n,1) if(!vis[i]) dfs(i);if(!ct){cout<<m<<'\n';rep(i,1,m,1) cout<<i<<' ';return 0;}vis.reset();rep(i,1,n,1) if(!vis[i]) dfs1(i);if(ct == 1) ans.emplace_back(eid);cout<<ans.size()<<'\n';sort(ans.begin(),ans.end());for(auto i:ans) cout<<i<<' ';
}
[中山市选] 杀人游戏
一眼下去答案为\(\frac{n-缩点后入度为0的点的个数}{n}\)。然后喜提30pts。
考虑哪里有问题呢?贪心的想,我们可以将强连通分量中个数为\(1\)且所连的点的入度都\(>1\)的点放在最后一个询问,如果其它点都确定了,那么这个点显然不用问,答案为\(\frac{n-缩点后入度为0的点的个数}{n}\)。
本题卡精度,输出答案时应加上eps。
点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCALauto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#elseauto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
const int N = 1e5 + 10;
#define eb emplace_back
int n,m;vector<int> e[N];
int dfn[N],low[N],tim,sta[N],top;
int tot = 0,g[N],u[N],v[N],d[N],siz[N],ct[N],out[N];
bitset<N> insta;set<int> pd[N];
void Tarjan(int x){dfn[x] = low[x] = ++tim;sta[++top] = x;insta[x] = true;for(auto y:e[x]){if(!dfn[y]) Tarjan(y),low[x] = min(low[x],low[y]);else if(insta[y]) low[x] = min(low[x],dfn[y]);}if(dfn[x] == low[x]){int y;tot++;do{y = sta[top--];g[y] = tot;insta[y] = false;siz[tot]++;}while(y != x);}
}
vector<pair<int,int> > E;
signed main(){cin.tie(nullptr)->sync_with_stdio(false);cin>>n>>m;rep(i,1,m,1){int u,v;cin>>u>>v;if(pd[u].count(v)) continue;pd[u].insert(v);e[u].eb(v);E.eb(u,v);}rep(i,1,n,1) pd[i].clear();rep(i,1,n,1) if(!dfn[i]) Tarjan(i);for(auto [x,y]:E){if(g[x] == g[y]) continue;if(pd[g[x]].count(g[y])) continue;pd[g[x]].insert(g[y]);out[g[x]]++;d[g[y]]++;}ldb ans = 0;for(auto [x,y]:E){if(g[x] == g[y]) continue;if(d[g[y]] >= 2) ct[g[x]]++;}rep(i,1,tot,1){if(!d[i] && ct[i] == out[i] && siz[i] == 1){ans -= 1;break;}}rep(i,1,tot,1){if(!d[i])ans += 1;}cout<<fixed<<setprecision(6);cout<<1.0*(n-ans)/n+1e-9<<'\n';
}
[NOI2018] 归程
模板:kruskal重构树。
就是用kruskal时,将两个点中间创建一个虚点,点权记为边权。
有如下性质:
- 两个点之间的所有简单路径上最大边权的最小值 = 最小生成树上两个点之间的简单路径上的最大值 = Kruskal 重构树上两点之间的 LCA 的权值。
- 如果以最小生成树的方式建树,那么建出的树是大根堆的形式。
本题则求最大生成树,就利用小根堆的性质,建出kruskal重构树后,每个点维护子树内\(1\)到子树内的点的最小值。
由于不会倍增,考虑树剖暴力跳,如果发现链顶无法达到,那么就在这条重链上二分即可。注意树剖清空,不然会导致奇怪错误。
时间复杂度\(O(m\log m + q\log n)\)。
点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCALauto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#elseauto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
#define int ll
#define eb emplace_back
const int N = 4e5 + 10;
vector<pair<int,int> > e[N],t[N];
struct Edge{int x,y,l,a;}edge[N];
int n,m,vtot,fa[N],siz[N],son[N],top[N],dfn[N],rdfn[N],tim,dep[N],dis[N],lastans;
int v,p,q,k,s;
ll dist[N];
bitset<N> vis;
void dijkstra(int s = 1){memset(dist,0x3f,sizeof dist);vis.reset();priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q;dist[s] = 0;q.emplace(0,s);while(q.size()){int x = q.top().second;q.pop();if(vis[x]) continue;vis[x] = true;for(auto [y,w]:e[x]){if(dist[y] > dist[x] + w){dist[y] = dist[x] + w;q.emplace(dist[y],y);}}}
}
struct DSU{vector<int> fa;void init(int n){fa.resize(n+1); rep(i,1,n,1) fa[i] = i;}int get_fa(int x){while(x ^ fa[x]) x = fa[x] = fa[fa[x]];return x;}bool Merge(int x,int y){x = get_fa(x),y = get_fa(y);if(x == y) return false;if(x > y) swap(x,y);return fa[x] = y,true;}
}D;
void dfs1(int x){dep[x] = dep[fa[x]] + 1;siz[x] = 1;for(auto [y,w]:t[x]){if(y == fa[x]) continue;dis[y] = w;fa[y] = x;dfs1(y);siz[x] += siz[y];dist[x] = min(dist[x],dist[y]);if(siz[son[x]] < siz[y]) son[x] = y;}
}
void dfs2(int x,int tp){top[x] = tp;rdfn[dfn[x] = ++tim] = x;if(son[x]) dfs2(son[x],tp);else return;for(auto [y,w]:t[x]){if(y == fa[x] || y == son[x]) continue;dfs2(y,y);}
}
void init(){rep(i,1,n*2+10,1) e[i].clear(),t[i].clear();memset(fa,0,sizeof fa);memset(siz,0,sizeof siz);memset(dfn,0,sizeof dfn);memset(rdfn,0,sizeof rdfn);memset(dep,0,sizeof dep);memset(top,0,sizeof top);memset(son,0,sizeof son);sort(edge+1,edge+1+m,[](Edge x,Edge y){return x.a > y.a;});D.init(n*2+10);rep(i,1,m,1){auto [x,y,l,a] = edge[i];e[x].eb(y,l);e[y].eb(x,l);if(D.get_fa(x) == D.get_fa(y)) continue;vtot++;t[vtot].eb(D.get_fa(x),a);t[vtot].eb(D.get_fa(y),a);t[D.get_fa(x)].eb(vtot,a);t[D.get_fa(y)].eb(vtot,a);D.fa[D.get_fa(x)] = vtot;D.fa[D.get_fa(y)] = vtot;}dijkstra();dfs1(vtot);tim = 0;dfs2(vtot,vtot);
}
int get(int v,int p){int x = v,fx = top[x];while(x && dis[fx] > p) x = fa[fx],fx = top[x];int l = dfn[fx],r = dfn[x],res = 0;while(l <= r){int mid = (l + r) >> 1;if(dis[rdfn[mid]] <= p) res = rdfn[mid],l = mid + 1;else r = mid - 1;}if(!res || res == 1) return 0;return dist[res];
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);
int T;cin>>T;
rep(Test,1,T,1){cin>>n>>m;vtot = n;lastans = 0;rep(i,1,m,1)cin>>edge[i].x>>edge[i].y>>edge[i].l>>edge[i].a;init();cin>>q>>k>>s;rep(test,1,q,1){cin>>v>>p;v = (v+k*lastans - 1)%n+1;p = (p+k*lastans)%(s+1);cout<<(lastans = get(v,p))<<'\n';}
}
}
Xor-MST
考虑Boruvka算法,那么就只需要考虑如果对于每个点,快速求出不在其连通块中最小连边。
求异或最小值,考虑01-trie,建一个全局trie,然后对于每个连通块,维护每个连通块的trie,然后记录每个节点的size,对于每个点,在全局trie中查找,如果减去其所在连通块中的size仍有,正常跑就行,合并两个连通块的时候,启发式合并它们的trie即可。
时间复杂度\(O(n\log n\log V)\),空间复杂度\(O(n\log V)\)。
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace __gnu_pbds;
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCALauto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#elseauto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = long double;using ldb = long double;
const int N = 2e5 + 10;
const ll inf = 1e15;
int n,a[N],rt[N],to[N];
ll mn[N];
struct Trie{int tree[N*60][2],siz[N*60],tot,ed[N*60];void insert(int &x,int dep,int w,int id){if(!x) x = ++tot;if(dep < 0) return ed[x] = id,siz[x] = 1,void();int c = w>>dep&1;insert(tree[x][c],dep-1,w,id);siz[x]++;}int Merge(int x,int y){if(!x || !y) return x|y;tree[x][0] = Merge(tree[x][0],tree[y][0]);tree[x][1] = Merge(tree[x][1],tree[y][1]);siz[x] = siz[tree[x][0]] + siz[tree[x][1]];ed[x] = ed[y];return x;}pair<int,int> get(int x,int pre,int w){int ans = 0;drep(i,30,0,1){int c = w>>i&1;if(tree[x][c] && siz[tree[x][c]] - siz[tree[pre][c]] > 0) x = tree[x][c],pre = tree[pre][c];else ans |= 1<<i,x = tree[x][c^1],pre = tree[pre][c^1];}return make_pair(ans,ed[x]);}
}T;
struct DSU{vector<int> fa,siz;int tot;void init(int n){tot = n;fa.resize(n+1),siz.resize(n+1,1);rep(i,1,n,1) fa[i] = i;}int get_fa(int x){while(x ^ fa[x]) x = fa[x] = fa[fa[x]];return x;}pair<int,int> Merge(int x,int y){x = get_fa(x),y = get_fa(y);if(x == y) return make_pair(0,0);tot--;if(siz[x] > siz[y]) swap(x,y);fa[x] = y;siz[y] += siz[x];return make_pair(x,y);}
}D;
signed main(){cin.tie(nullptr)->sync_with_stdio(false);vector<int> num;cin>>n;rep(i,1,n,1) cin>>a[i],num.emplace_back(a[i]);sort(a+1,a+1+n);n = unique(a+1,a+1+n) - a - 1;rep(i,1,n,1) T.insert(rt[0],30,a[i],i),T.insert(rt[i],30,a[i],i);D.init(n);bitset<N> vis;ll ans = 0;int tot = 0;while(D.tot != 1){tot++;rep(i,1,n,1) mn[i] = inf;rep(i,1,n,1){auto res = T.get(rt[0],rt[D.get_fa(i)],a[i]);if(res.first < mn[D.get_fa(i)]) mn[D.get_fa(i)] = res.first,to[D.get_fa(i)] = D.get_fa(res.second);}bool flag = true;rep(i,1,n,1){if(mn[i] == inf) continue;flag &= false;auto res = D.Merge(i,to[i]);if(res.first) T.Merge(rt[res.second],rt[res.first]),ans += mn[i];}}cout<<ans<<'\n';
}
\(to\;be\;continued\)