LGP4768 [NOI 2018] 归程 学习笔记
LGP4768 [NOI 2018] 归程 学习笔记
题意简述
给定一个 \(n\) 点 \(m\) 边的无向连通图。每条边有两个权值 \(w,z\)。
\(q\) 次询问,每次给定 \(s,p\),你要选择一个点 \(t\) 并最小化 \(\sum_{e\in E(t\to 1)}w_e\),其中 \(t\) 需要满足 \(\exist E(s\to t),\forall e\in E,z_e>p\)(说人话就是:)。强制在线。
\(n\le 2\times 10^5,m\le 4\times 10^5,q\le 4\times 10^5\)。
时限 \(\text{4.00s}\)。
做法解析
这里给出一种使用 Kruskal 重构树的做法。OI-wiki相关条目。
为什么是 Kruskal 重构树?因为这题实际上做的事情就是,对于每个询问我们要找到所有和它以“路径上最小边权不小于 \(p\)”这一条件连通的点——这个形式太典型了。
按照 \(z\) 建一棵小根 Kruskal 重构树。这样,对于每个询问,任意边结点 \(u\) 只要满足 \(z_u>p\) 就意味着其子树内所有点都可以无代价互通。所以我们用倍增找到最浅的 \(s\) 的祖先 \(a\) 满足 \(z_a>p\),答案就是 \(\min_{v\in \text{subtree}(a)}\text{dis}(v\to 1)\)。
代码实现
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=4e5+5,MaxNb=23;
int N,M,X,Y,W,Z,Q,Typ,S;
struct edge{int u,v,w,z;}E[MaxN];
int getv(edge &e,int x){return e.u==x?e.v:e.u;}
vector<int> Gr[MaxN];
void addedge1(int u,int v,int w,int z,int i){
E[i]={u,v,w,z};
Gr[X].push_back(i);
Gr[Y].push_back(i);
}
uint dis[MaxN];
struct anod{
int u;uint d;
friend bool operator>(anod a,anod b){return a.d>b.d;}
};
priority_queue<anod,vector<anod>,greater<anod> > pq;
void dijkstra(int s){
fill(dis,dis+N*2,Ihu7f);
dis[s]=0,pq.push({s,0});
while(pq.size()){
auto [u,d]=pq.top();
pq.pop();if(d>dis[u])continue;
for(int x : Gr[u]){
auto e=E[x];
int v=getv(e,u),w=e.w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
pq.push({v,dis[v]});
}
}
}
}
int K[MaxN],kfa[MaxN][MaxNb];
vector<int> Kr[MaxN];uint ans[MaxN],fans;
void addedge2(int c,int u,int v){
Kr[c].push_back(u);
Kr[c].push_back(v);
}
struct UnionFind{
int n,ufa[MaxN];
void init(int x){n=x;for(int i=1;i<=n;i++)ufa[i]=i;}
int find(int u){return ufa[u]==u?u:ufa[u]=find(ufa[u]);}
void mudge(edge e){
auto [u,v,w,z]=e;
int fu=find(u),fv=find(v);
if(fu==fv)return;
n++,ufa[fu]=ufa[fv]=ufa[n]=n;
addedge2(n,fu,fv),K[n]=z;
}
}UniFd;
bool cmpz(edge a,edge b){return a.z>b.z;}
void dfs(int u){
ans[u]=dis[u];
for(auto v : Kr[u]){
kfa[v][0]=u;
dfs(v),minner(ans[u],ans[v]);
}
}
void kruskal(){
UniFd.init(N);sort(E+1,E+M+1,cmpz);
for(int i=1;i<=M;i++)UniFd.mudge(E[i]);
dfs(UniFd.n);
for(int i=1;i<=log2(N*2);i++){
for(int u=1;u<N*2;u++){
kfa[u][i]=kfa[kfa[u][i-1]][i-1];
}
}
}
uint solve(int u,int lim){
for(int i=log2(N*2);i>=0;i--)if(K[kfa[u][i]]>lim)u=kfa[u][i];
return ans[u];
}
void befinit(){
K[0]=-1,fans=0;
for(int i=1;i<N*2;i++)Kr[i].clear(),Gr[i].clear();
}
void mian(){
readis(N,M),befinit();
for(int i=1;i<=M;i++){
readis(X,Y,W,Z);
addedge1(X,Y,W,Z,i);
}
dijkstra(1),kruskal();
readis(Q,Typ,S);
for(int i=1;i<=Q;i++){
readis(X,Z);
X=(X+Typ*fans-1)%N+1;
Z=(Z+Typ*fans)%(S+1);
fans=solve(X,Z);
writil(fans);
}
}
int Tcn;
int main(){
readi(Tcn);
while(Tcn--)mian();
return 0;
}
浙公网安备 33010602011771号