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
",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,int pre)
{
    dep[x]=dep[pre]+1;
    g[x][0]=pre;
    for(int i=1;i<=21;i++) g[x][i]=g[g[x][i-1]][i-1];
    for(int i=head2[x];i;i=e[i].nxt)
    {
        int v=e[i].to;
        dfs(v,x);
        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)>0&&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=n+1;i<=2*n;i++) kkk[i].l=0x3f3f3f3f;
        dij(1);
        kruskal();
        dfs(cnt,0);
        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
",lastans);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fengxunling/p/10359135.html