[NOI2018] 归程
很奇怪的是,我写这道题似乎比写那道peak还顺利一点。
虽然本蒟蒻到今天才写出这道题,但对于这道梗题相信很多Oier都有所耳闻,没错它就是OI名梗“关于SPFA,它死了”的来源(但其实对我来说并木有什么影响,反正我也不太想写SPFA)。
说回正题。题目中明确说了有一些询问,每个询问下你只能走边权大于某个值的所有边,而这是重构树的标志性词语,只不过在跑生成树时改成跑最大生成树即可。那么还是套倍增,我们就使得人物可以到达且只能到达重构树上某个子树内的所有节点(树根通过倍增找),那么我们要做的就是考虑树内哪个节点涉水到1号的距离最小,那就是最短路后预处理就可以了。写起来异常顺利,半个小时多一丢丢就水过了这道名题。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define zczc
using namespace std;
const int N=200010;
const int M=400010;
const int S=22;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
inline int min(int s1,int s2){
return s1<s2?s1:s2;
}
int m,n;
struct ee{int p1,p2,val;}se[M];
inline bool cmp(ee s1,ee s2){return s1.val>s2.val;}
struct edge{int t,v,next;}e[M<<1];
int esum,head[N];
inline void add(int fr,int to,int val){
e[++esum]=(edge){to,val,head[fr]};head[fr]=esum;
}
int lc[N*2],rc[N*2],data[N*2];
int cnt,f[N*2];
inline int find(int wh){return f[wh]==wh?wh:f[wh]=find(f[wh]);}
int dis[N];
struct node{int pl,dis;};
bool operator <(node s1,node s2){return s2.dis<s1.dis;}
priority_queue<node>q;
void dij(){
memset(dis,0x3f,sizeof(dis));
while(!q.empty())q.pop();
dis[1]=0;q.push((node){1,0});
while(!q.empty()){
int wh=q.top().pl,dd=q.top().dis;q.pop();
if(dd>dis[wh])continue;
for(int i=head[wh];i;i=e[i].next){
int nd=dd+e[i].v,th=e[i].t;
if(nd<dis[th]){
dis[th]=nd;q.push((node){th,nd});
}
}
}
}
int an[N<<1],nxt[N<<1][25];
void dfs(int wh,int fa){
nxt[wh][0]=fa;
for(int i=1;i<=S;i++)nxt[wh][i]=nxt[nxt[wh][i-1]][i-1];
if(wh<=m){an[wh]=dis[wh];return;}
dfs(lc[wh],wh);dfs(rc[wh],wh);
an[wh]=min(an[lc[wh]],an[rc[wh]]);return;
}
void solve(){
esum=0;memset(head,0,sizeof(head));
memset(lc,0,sizeof(lc));
memset(rc,0,sizeof(rc));
memset(data,0,sizeof(data));
memset(nxt,0,sizeof(nxt));
read(m);read(n);esum=0;
int p1,p2,v1,v2;
for(int i=1;i<=n;i++){
read(p1);read(p2);read(v1);read(v2);
se[i].p1=p1,se[i].p2=p2,se[i].val=v2;
add(p1,p2,v1);add(p2,p1,v1);
}
sort(se+1,se+n+1,cmp);
for(int i=1;i<=m*2;i++)f[i]=i;cnt=m;
for(int i=1;i<=n;i++){
int f1=find(se[i].p1),f2=find(se[i].p2);
if(f1==f2)continue;
f[f1]=f[f2]=++cnt;lc[cnt]=f1,rc[cnt]=f2;data[cnt]=se[i].val;
}
dij();dfs(cnt,0);
int q,k,ss,lan=0,s,d;
read(q);read(k);read(ss);
while(q--){
read(s);read(d);
s=(s+lan*k-1)%m+1;
d=(d+k*lan)%(ss+1);
for(int i=S;i>=0;i--){
if(data[nxt[s][i]]>d)s=nxt[s][i];
}
printf("%d\n",lan=an[s]);
}
}
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
#endif
int test;
read(test);
while(test--){
solve();
}
return 0;
}
一如既往,万事胜意