#Kruskal重构树,Dijkstra,倍增#洛谷 4768 [NOI2018]归程

题目传送门


分析

首先Dijkstra是必需的(关于SPFA,它死了233)
无向图,所以先求出1号节点到所有点的距离,然后肯定希望起点能驾驶到离一号点最短的汽车可到的地方
但是怎么办,考虑海拔大的边肯定会更想选,那为什么不用Kruskal建出一棵最大生成树
但是怎么求呢,Kruskal重构树横空出世,通过用新点连接原来两点,建起一棵\(2n-1\)个点的树
那有什么用呢,这棵树变成了二叉堆,在本题中还是小根堆,也就是两点LCA代表了重构树路径上最小边
那边再求个最小值不就可以用倍增解决了吗


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define rr register
using namespace std;
const int N=400011;
struct rec{int x,y,w,c;}T[N]; struct node{int y,w,next;}e[N<<1]; struct Node{int y,next;}E[N];
int ls[N>>1],hs[N],dis[N],h[N],dep[N],n,m,k,K,cnt,nnt,f[N][20],Q,opt,S,fat[N]; pair<int,int>heap[N>>1];
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
    return ans;
}
inline void add(int x,int y,int w){e[++k]=(node){y,w,ls[x]}; ls[x]=k;}
inline void Add(int x,int y){E[++K]=(Node){y,hs[x]},hs[x]=K;}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void Push(pair<int,int>w){
    heap[++cnt]=w;
    rr int x=cnt;
    while (x>1){
        if (heap[x>>1]>heap[x])
            swap(heap[x>>1],heap[x]),x>>=1;
        else return;
    }
}
inline void Pop(){
    heap[1]=heap[cnt--];
    rr int x=1;
    while ((x<<1)<=cnt){
        rr int y=x<<1;
        if (y<cnt&&heap[y+1]<heap[y]) ++y;
        if (heap[y]<heap[x]) swap(heap[y],heap[x]),x=y;
            else return;
    }
}
inline void Dijkstra(){
    dis[1]=0,heap[++cnt]=make_pair(0,1);
    while (cnt){
    	rr int x=heap[1].second,t=heap[1].first;
    	Pop(); if (t!=dis[x]) continue;
    	for (rr int i=ls[x];i;i=e[i].next)
    	if (dis[e[i].y]>dis[x]+e[i].w){
    		dis[e[i].y]=dis[x]+e[i].w;
			Push(make_pair(dis[e[i].y],e[i].y));
		}
	}
}
bool cmp(rec x,rec y){return x.c>y.c;}
inline signed getf(int u){return fat[u]==u?u:fat[u]=getf(fat[u]);}
inline void Kruskal(){
    for (rr int i=1;i<n*2;++i) fat[i]=i;
    for (rr int i=1,tot=0;i<=m;++i){
        rr int fa=getf(T[i].x),fb=getf(T[i].y);
        if (fa!=fb){
            fat[fa]=fat[fb]=++nnt,h[nnt]=T[i].c;
            Add(nnt,fa),Add(nnt,fb);
            if (++tot==n-1) return;
        }
    }
}
inline void dfs(int x,int fa){
    dep[x]=dep[fa]+1,f[x][0]=fa;
    for (rr int i=1;i<20;++i) f[x][i]=f[f[x][i-1]][i-1];
    for (rr int i=hs[x];i;i=E[i].next)
        dfs(E[i].y,x),dis[x]=min(dis[x],dis[E[i].y]);
}
inline signed GetF(int x,int H){
    for (rr int i=19;~i;--i)
    if (dep[x]>=(1<<i)&&h[f[x][i]]>H) x=f[x][i];
    return dis[x];
}
signed main(){
    for (rr int Test=iut();Test;--Test){
        memset(ls,0,sizeof(ls)),memset(f,0,sizeof(f));
        memset(dep,0,sizeof(dep)),memset(hs,0,sizeof(hs));
        memset(h,0,sizeof(h)),memset(dis,0x3f,sizeof(dis));
        n=iut(),m=iut(),k=K=1,nnt=n;
        for (rr int i=1;i<=m;++i){
            T[i]=(rec){iut(),iut(),iut(),iut()};
            add(T[i].x,T[i].y,T[i].w);
            add(T[i].y,T[i].x,T[i].w);
        }
        Dijkstra(),sort(T+1,T+1+m,cmp),Kruskal(),
        dfs(nnt,0),Q=iut(),opt=iut(),S=iut();
        for (rr int lastans=0;Q;Q--){
            rr int G=iut(),H=iut();
            if (opt) G=(G+lastans-1)%n+1,H=(H+lastans)%(S+1);
            print(lastans=GetF(G,H)),putchar(10);
        }
    }
    return 0;
}
posted @ 2020-02-23 23:27  lemondinosaur  阅读(111)  评论(0编辑  收藏  举报