学习自墨染空大佬博客
墨染空大佬总结的太好了,下面的流程部分基本复制大佬的总结。
- 将所有边按边权从小到大排序
- 顺序遍历每条边 ( u , v , w ) (u,v,w) (u,v,w),若 u , v u,v u,v已经联通跳过,否则建立一个新点 x x x,让 x x x 作为 p u p_u pu 与 p v p_v pv 的父亲(即连 x ⇒ p u x⇒p_u x⇒pu 和 x ⇒ p v x⇒p_v x⇒pv 的有向边),然后让 p u = p v = x p_u=p_v=x pu=pv=x。这个新点的点权是 w w w。
O ( m l o g m ) O(mlogm) O(mlogm)
注意:对于某些性质的证明请直接阅读墨染空大佬博客
对于Kruskal 重构树能够解决的问题:能够代替可持久化并查集并且时间复杂度更优,好像也就能解决这类问题
考虑离线:我们可以按照海拔从大到小进行询问,便询问边加边使用并查集维护每个连通块的最小值即可。
由于强制在线我们可以按照海拔从小到大建立可持久化并查集,然后对于每一个询问二分某个版本查询即可。
上述做法是并查集做法。
如果用Kruskal 重构树,只需要按照海拔从大到小建立Kruskal 重构树,每个询问找到海拔最小的祖先节点,然后查询子树最小权值即可。
// P4768 [NOI2018] 归程 https://www.luogu.com.cn/problem/P4768
#include
using namespace std;
using pii=pair<int,int>;
constexpr int N(200005),M=(400005),INF(0x3f3f3f3f);
struct Edge
{
int u,v,w;
bool operator<(const Edge &o)const
{
return w>o.w;
}
}E[M];
int h[N],e[M<<1],ne[M<<1],w[M<<1],idx;
void add(int a,int b,int c){e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;}
int d[N],st[N];
int n,m;
priority_queue<pii,vector<pii>,greater<pii>> q;
void dij()
{
for(int i=1;i<=n;i++) d[i]=INF,st[i]=0;
d[1]=0;
q.push({0,1});
while(q.size())
{
int u=q.top().second;q.pop();
if(st[u]) continue;
st[u]=1;
for(int i=h[u];i!=-1;i=ne[i])
{
int v=e[i];
if(d[v]>d[u]+w[i])
{
d[v]=d[u]+w[i];
q.push({d[v],v});
}
}
}
}
vector<int> G[N<<1];
int fa[N<<1];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int tot,kv[N<<1];
void Merge(int u,int v,int w)
{
u=find(u),v=find(v);
if(u==v) return;
fa[u]=fa[v]=++tot;
kv[tot]=w;
G[tot].push_back(u);G[tot].push_back(v);
}
int Fa[N<<1][21],val[N<<1];
void dfs(int u)
{
val[u]=u<=n?d[u]:INF;
for(int v:G[u])
{
Fa[v][0]=u;
for(int k=1;k<=18;k++) Fa[v][k]=Fa[Fa[v][k-1]][k-1];
dfs(v);
val[u]=min(val[u],val[v]);
}
}
int main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int Tc;cin>>Tc;
while(Tc--)
{
cin>>n>>m;
for(int i=1;i<=n;i++) h[i]=-1;idx=0;
for(int i=1;i<=m;i++)
{
int u,v,l,a;cin>>u>>v>>l>>a;
add(u,v,l);add(v,u,l);
E[i]={u,v,a};
}
dij();
sort(E+1,E+1+m);
for(int i=1;i<=2*n-1;i++) fa[i]=i;tot=n;
for(int i=1;i<=2*n-1;i++) G[i].clear();
for(int i=1;i<=m;i++) Merge(E[i].u,E[i].v,E[i].w);
dfs(tot);
int Q,K,S;cin>>Q>>K>>S;
int lastans=0;
while(Q--)
{
int v,p;cin>>v>>p;
v=(v+K*lastans-1)%n+1;
p=(p+K*lastans)%(S+1);
for(int k=18;k>=0;k--)
if(kv[Fa[v][k]]>p) v=Fa[v][k];
lastans=val[v];
cout<<lastans<<'\n';
}
}
return 0;
}
// P4768 [NOI2018] 归程 https://www.luogu.com.cn/problem/P4768
#include
using namespace std;
using pii=pair<int,int>;
constexpr int N(200005),M=(400005),INF(0x3f3f3f3f);
struct Edge
{
int u,v,w;
bool operator<(const Edge &o)const
{
return w<o.w;
}
}E[M];
int h[N],e[M<<1],ne[M<<1],w[M<<1],idx;
void add(int a,int b,int c){e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;}
int d[N],vis[N];
int n,m;
priority_queue<pii,vector<pii>,greater<pii>> q;
void dij()
{
for(int i=1;i<=n;i++) d[i]=INF,vis[i]=0;
d[1]=0;
q.push({0,1});
while(q.size())
{
int u=q.top().second;q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=h[u];i!=-1;i=ne[i])
{
int v=e[i];
if(d[v]>d[u]+w[i])
{
d[v]=d[u]+w[i];
q.push({d[v],v});
}
}
}
}
struct Array
{
struct Segment
{
int l,r,v;
}t[N*4+M*19];
int rt[M],cnt;
void build(int &u,int l,int r,int c)
{
t[u=++cnt]={0,0,0};
if(l==r)
{
if(c==1) t[u].v=l;
else if(c==2) t[u].v=1;
else if(c==3) t[u].v=d[l];
return;
}
int mid=l+r>>1;
build(t[u].l,l,mid,c),build(t[u].r,mid+1,r,c);
}
void update(int &u,int pre,int l,int r,int pos,int v)
{
t[u=++cnt]=t[pre];
if(l==r) return t[u].v=v,void();
int mid=l+r>>1;
if(pos<=mid)
update(t[u].l,t[pre].l,l,mid,pos,v);
else
update(t[u].r,t[pre].r,mid+1,r,pos,v);
}
int query(int u,int l,int r,int pos)
{
if(l==r) return t[u].v;
int mid=l+r>>1;
if(pos<=mid)
return query(t[u].l,l,mid,pos);
else
return query(t[u].r,mid+1,r,pos);
}
void clear(){cnt=0;}
int inline get(int u,int pos){
return query(rt[u],1,n,pos);
}
void inline ins(int u,int pos,int v)
{
update(rt[u],rt[u],1,n,pos,v);
}
}sz,fa,val;
int find(int u,int x)
{
int f=fa.get(u,x);
return x==f?x:find(u,f);
}
void inline merge(int v, int a, int b) {
a=find(v,a),b=find(v,b);
if(a==b)return;
int sa=sz.get(v,a),sb=sz.get(v,b);
if (sa>sb) swap(a,b),swap(sa,sb);
int va=val.get(v,a),vb=val.get(v,b);
fa.ins(v,a,b);sz.ins(v,b,sa+sb);
val.ins(v,b,min(va, vb));
}
int b[M],tot;
void clear()
{
sz.clear(),fa.clear(),val.clear();
for(int i=1;i<=n;i++) h[i]=-1;idx=0;
tot=0;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int Tc;cin>>Tc;
while(Tc--)
{
cin>>n>>m;clear();
for(int i=1;i<=m;i++)
{
int u,v,l,a;cin>>u>>v>>l>>a;
add(u,v,l);add(v,u,l);
E[i]={u,v,a};
b[i]=a;
}
dij();
sort(E+1,E+1+m);
sort(b+1,b+1+m);tot=unique(b+1,b+1+m)-b-1;b[++tot]=2e9;
fa.build(fa.rt[tot],1,n,1);
sz.build(sz.rt[tot],1,n,2);
val.build(val.rt[tot],1,n,3);
for(int i=tot-1,j=m;i>=1;i--)
{
fa.rt[i]=fa.rt[i+1];
sz.rt[i]=sz.rt[i+1];
val.rt[i]=val.rt[i+1];
while(j&&E[j].w>=b[i])
{
merge(i,E[j].u,E[j].v);
j--;
}
}
int Q,K,S;cin>>Q>>K>>S;
int lastans=0;
while(Q--)
{
int v,p;cin>>v>>p;
v=(v+K*lastans-1)%n+1;
p=(p+K*lastans)%(S+1);
int id=upper_bound(b+1,b+1+tot,p)-b;
lastans=val.get(id,find(id,v));
cout<<lastans<<'\n';
}
}
return 0;
}
要加哟哦~