NOI2018 归程
作者:互联网
题目链接:戳我
kruskal重构树做法。
预处理每个点到根的最短路。
将边从大到小排序,然后建树,建出来的kruskal生成树就是一个小根堆。
我们尽可能的从当前点向上面跳。(也就是带限制“海拔大于等于p”的树上倍增)
然后呢,因为是一个小根堆,我们可以免费走到该点子树以内任意一个点,所以我们来一个dfs找出字数内到1最短路最短的答案即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define MAXN 400010
using namespace std;
int t,n,m,tt,tt2,Q,K,S,v0,p0,cnt,lastans;
int dist[MAXN],done[MAXN],head[MAXN<<1],head2[MAXN<<1],fa[MAXN<<1],g[MAXN][22],dep[MAXN];
struct Line{int u,v,len,h;}line[MAXN];
struct Node{
int u,d;
friend bool operator <(struct Node x,struct Node y)
{return x.d>y.d;}
}node[MAXN<<1];
struct Edge{int nxt,to,dis,hei;}edge[MAXN<<2],e[MAXN<<2];
struct Node2{int u,v,l,a;}kkk[MAXN<<2];
inline void add(int from,int to,int dis)
{
edge[++tt].nxt=head[from],edge[tt].to=to,edge[tt].dis=dis,head[from]=tt;
}
inline void add2(int from,int to){e[++tt2].nxt=head2[from],e[tt2].to=to,head2[from]=tt2;}
inline bool cmp(struct Line x,struct Line y){return x.h>y.h;}
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void dij(int s)
{
priority_queue<Node>q;
memset(done,0,sizeof(done));
memset(dist,0x3f,sizeof(dist));
q.push((Node){s,0});dist[s]=0;
while(!q.empty())
{
int u=q.top().u;q.pop();
if(done[u]) continue;
done[u]=1;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(dist[u]+edge[i].dis<dist[v])
dist[v]=dist[u]+edge[i].dis,q.push((Node){v,dist[v]});
}
}
for(int i=1;i<=n;i++) kkk[i].l=dist[i];
}
inline void kruskal()
{
for(int i=1;i<=n*2;i++) fa[i]=i;
sort(&line[1],&line[m+1],cmp);
int tot=0;
cnt=n;
for(int i=1;i<=m;i++)
{
int u=line[i].u,v=line[i].v;
int a=find(u),b=find(v);
if(a!=b)
{
cnt++;
fa[a]=cnt,fa[b]=cnt,fa[cnt]=cnt;
//printf("u=%d v=%d a=%d b=%d 长度=%d 海拔=%d cnt=%d\n",u,v,a,b,line[i].len,line[i].h,cnt);
add2(cnt,a);add2(cnt,b);
kkk[cnt].a=line[i].h;
tot++;
}
if(tot==n-1) break;
}
}
inline void dfs(int x)
{
dep[x]=dep[fa[x]]+1;
g[x][0]=fa[x];
for(int i=head2[x];i;i=e[i].nxt)
{
int v=e[i].to;
dfs(v);
kkk[x].l=min(kkk[x].l,kkk[v].l);
}
}
inline int query(int x,int y){
for(int i=21;i>=0;--i)
if(dep[x]>(1<<i)&&kkk[g[x][i]].a>y)
x=g[x][i];
return kkk[x].l;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d",&t);
while(t--)
{
memset(fa,0,sizeof(fa));
memset(head,0,sizeof(head));
memset(head2,0,sizeof(head2));
tt=tt2=lastans=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%d",&line[i].u,&line[i].v,&line[i].len,&line[i].h);
add(line[i].u,line[i].v,line[i].len),add(line[i].v,line[i].u,line[i].len);
}
for(int i=1;i<=2*n;i++) kkk[i].l=0x3f3f3f3f;
dij(1);
kruskal();
for(int i=1;i<=cnt;i++)
for(int j=1;j<=21;j++)
g[i][j]=g[g[i][j-1]][j-1];
dfs(cnt);
scanf("%d%d%d",&Q,&K,&S);
for(int i=1;i<=Q;i++)
{
scanf("%d%d",&v0,&p0);
int v=(v0+K*lastans-1)%n+1;
int p=(p0+K*lastans)%(S+1);
lastans=query(v,p);
printf("%d\n",lastans);
}
}
return 0;
}
标签:dist,int,memset,done,sizeof,include,NOI2018,归程 来源: https://www.cnblogs.com/fengxunling/p/10359135.html