牛客遇到一道题目,1e7组询问,查询最小生成树上某两个点路径上边权最大值。
貌似是一道克鲁斯卡尔重构树的模板问题,依照克鲁斯卡尔求最小生成树的做法,把边按权值从小到大排序,枚举(x,y,val)加边时,不直接加边,先访问到x,y当前并查集内的根fx,fy,然后新开一个点np,把fx和fy都挂到np下面当儿子,np点的权值则是该边边权val。
性质,这样建出来的树两点间lca的权值就是原最小生成树两点间路径边权最大值。
因此问题变成了O(1)lca,经典的求欧拉序加st表维护即可。
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define sc second
#define pb push_back
#define ll long long
#define trav(v,x) for(auto v:x)
#define all(x) (x).begin(), (x).end()
#define VI vector<int>
#define VLL vector<ll>
using namespace std;
const int N = 2e6 + 100;
const ll mod = 1e9 + 7;
struct E{
int x, y, val;
void in()
{
cin >> x >> y >> val;
}
}edge[N];
int n, m, ff[N];
int find(int x)
{return ff[x] == x ? x : ff[x] = find(ff[x]);}
bool cmp(E x, E y)
{return x.val < y.val;}
vector<int> adj[N];
int dep[N], val[N], ol[N], fst[N], st[N][20];
int tim = 0;
void dfs(int x, int fa)
{
ol[++tim] = x;
fst[x] = tim;
trav(v, adj[x])
{
if(v == fa)
continue;
dep[v] = dep[x] + 1;
dfs(v, x);
ol[++tim] = x;
}
}
typedef unsigned long long ull;
ull myRand(ull &k1, ull &k2){
ull k3 = k1, k4 = k2;
k1 = k4;
k3 ^= (k3 <<23);
k2 = k3 ^ k4 ^ (k3 >>17) ^ (k4 >>26);
return k2 + k4;
}
pair<int,int>myRanq(ull&k1,ull&k2,int MAXN){
int x=myRand(k1,k2)%MAXN+1,y=myRand(k1,k2)%MAXN+1;
if(x>y)return make_pair(y,x);
else return make_pair(x,y);
}
int lgx[N * 3];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
for(int i = 1; i <= m; i++)
{
edge[i].in();
}
sort(edge + 1, edge + m + 1, cmp);
for(int i = 1; i <= n + n; i++)
ff[i] = i, val[i] = 0;
int llim = n + n - 1, nn;
nn = n;
for(int i = 1; i <= m; i++)
{
int x = edge[i].x;
int y = edge[i].y;
int fx = find(x);
int fy = find(y);
if(fx == fy)
continue;
++n;
ff[fx] = n;
ff[fy] = n;
adj[n].pb(fx);
adj[n].pb(fy);
val[n] = edge[i].val;
if(n == llim)break;
}
int rt = find(1);
dep[rt] = 1;
dfs(rt, 0);
for(int i = 1; i <= tim; i++)
st[i][0] = ol[i];
for(int lg = 1; lg < 20; lg++)
{
int len = (1 << lg);
int md = (len >> 1);
for(int i = 1; i + len - 1 <= tim; i++)
{
int nw = st[i][lg - 1];
int nx = i + md;
if(dep[st[nx][lg - 1]] < dep[nw])
nw = st[nx][lg - 1];
st[i][lg] = nw;
}
}
lgx[1] = 0;
for(int i = 2; i <= tim; i++)
lgx[i] = lgx[i >> 1] + 1;
int qq;
cin >> qq;
ull a1, a2;
cin >> a1 >> a2;
int res = 0;
for(int i = 1; i <= qq; i++)
{
pii qry = myRanq(a1, a2, nn);
int x = qry.fi;
int y = qry.sc;
x = fst[x], y= fst[y];
if(x > y)
swap(x, y);
int k = lgx[y - x + 1];
int ans = st[x][k];
int tmp = st[y - (1 << k) + 1][k];
if(dep[tmp] < dep[ans])
ans = tmp;
res ^= val[ans];
}
cout << res << '\n';
}