Boruvka 小记
(上场 Codeforces div.2 F题 没想出来,问了大佬 KarL05 才知道有除了 Kruskal 和 Prim 以外的一种生成树算法,故将其记录下来。)
算法内容大概是维护每个连通块连出的最小边,每次迭代中对于每个连通块找到连出的最小边,找完后合并。由于原图连通,每次迭代中连通块个数至少减半,故算法迭代次数不超过
算法详解:Boruvka 算法
CF888G Xor-MST
题目大意:
给出
数据范围:
题目难度:CF 2300*
知识储备:01-Trie / Boruvka
解析:
总之不能做出所有边后用 Kruskal 解决,考虑使用 Boruvka 。可以将所有
小技巧是把
时间复杂度:
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define ll long long
using namespace std;
inline ll read(){
ll x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const int N=2e5+5,inf=(1<<30);
int n,m,a[N],L[N*32],R[N*32],ch[2][N*32],rt,cnt;
//插入trie
void insert(int &p,int id,int dep){
if(!p)p=++cnt;
if(!L[p])L[p]=id;
R[p]=id;
if(dep==-1)return;
insert(ch[(a[id]>>dep)&1][p],id,dep-1);
}
//查询异或最小值
ll Q(int p,int x,int dep){
if(dep==-1)return 0;
int v=(x>>dep)&1;
if(ch[v][p])return Q(ch[v][p],x,dep-1);
else return Q(ch[v^1][p],x,dep-1)+(1<<dep);
}
#define ls ch[0][p]
#define rs ch[1][p]
ll dfs(int p,int dep){
if(dep==-1)return 0;
if(ls&&rs){
ll val=inf;
rep(i,L[ls],R[ls]){
val=min(val,Q(rs,a[i],dep-1)+(1<<dep));
}
return dfs(ls,dep-1)+dfs(rs,dep-1)+val;
}
if(ls)return dfs(ls,dep-1);
if(rs)return dfs(rs,dep-1);
return 0;
}
int main(){
n=read();
rep(i,1,n)a[i]=read();
sort(a+1,a+n+1);
rep(i,1,n)insert(rt,i,30);
printf("%lld\n",dfs(rt,30));
return 0;
}
CF1550E Jumping Around
题目大意:
数轴上有
数据范围:
题目难度:CF 2700*
知识储备:Boruvka
解析:
不难想到建最小生成树后判断
具体地,考虑使用 Boruvka ,由于该题的边权有特点,我们可以把所有位置放入 set 中,每次用 lower_bound 查询离
时间复杂度:
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define ll long long
using namespace std;
inline ll read(){
ll x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const int N=2e5+5,inf=1e9;
struct Edge{
int u,v,w;
friend bool operator <(const Edge &a,const Edge &b){
if(a.w!=b.w)return a.w<b.w;
if(min(a.u,a.v)!=min(b.u,b.v))
return min(a.u,a.v)<min(b.u,b.v);
return max(a.u,a.v)<max(b.u,b.v);
}
};
int n,q,s,D,fa[N],mn[N];
vector<int>comps[N];
bool merge(int u,int v){
u=fa[u],v=fa[v];
if(u==v)return 0;
if(comps[u].size()<comps[v].size())swap(u,v);
for(int x:comps[v]){
fa[x]=u;
comps[u].pb(x);
}
comps[v].clear();
return 1;
}
vector <pii> G[N];
void dfs(int u,int p,int d){
mn[u]=d;
for(auto e:G[u])if(e.fi!=p){
dfs(e.fi,u,max(d,e.se));
}
}
int main(){
n=read(),q=read(),s=read()-1,D=read();
vector <int> a(n);
rep(i,0,n-1){
comps[i]=vector<int>(1,i);
a[i]=read();
fa[i]=i;
}
vector<int>idx(a[n-1]+1);
rep(i,0,n-1)idx[a[i]]=i;
int cnt=n;
set<int>pos(a.begin(),a.end());
while(cnt>1){
vector <Edge> tmp;
for(const vector<int> &comp:comps)if(!comp.empty()){
for(int i:comp)pos.erase(a[i]);
Edge mn={-1,-1,inf};
for(int i:comp){//找最短边
for(int d:{-D,D}){
auto it = pos.lower_bound(a[i]+d);
if(it!=pos.end()){
int dis=abs(abs(a[i]-*it)-D);
mn=min(mn,{i,idx[*it],dis});
}
if(it!=pos.begin()){
it--;
int dis=abs(abs(a[i]-*it)-D);
mn=min(mn,{i,idx[*it],dis});
}
}
}
for(int i:comp)pos.insert(a[i]);
tmp.pb(mn);
}
for(auto e:tmp){//加边
if(merge(e.u,e.v)){
--cnt;
G[e.u].pb({e.v,e.w});
G[e.v].pb({e.u,e.w});
}
}
}
dfs(s,-1,0);
while(q--){
int i=read()-1,k=read();
puts(mn[i]<=k?"Yes":"No");
}
return 0;
}