BZOJ 5415: [Noi2018]归程(kruskal重构树)

解题思路

  (NOI2018)(Day1) (T1),当时打网络赛的时候不会做。学了一下(kruskal)重构树后发现问题迎刃而解了。根据(kruskal)的性质,如果要找从(u)出发,所走边权(>lim)的所能到达的点,可以将边从大到小排序,重构树后从(u)往上跳到点权(>lim)深度最浅的点,这个点子树的叶节点为所求点集合。有了这个以后就可以跑一遍从(1)开始的最短路,记(Min(i))表示重构树上(i)这个节点所有子树到(1)的最小值。然后对于每次询问,把刚才所说的深度最浅的点找出来,它的(Min)即为答案。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
 
using namespace std;
const int N=400005;
typedef long long LL;
 
inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return f?x:-x;
}
 
int n,m,q,K,S,w[N],f[N][22],T,val[N<<1];
int head[N],cnt,to[N<<1],nxt[N<<1],F[N],tot,num;
LL ans,Min[N];
 
struct Edge{
    int u,v,a,l;
    friend bool operator<(const Edge A,const Edge B){
        return A.a>B.a;
    }   
}edge[N];
 
struct Node{
    int id; LL w;
    friend bool operator<(const Node A,const Node B){
        return A.w>B.w;
    }
    Node(int _id=0,int _w=0) {id=_id; w=_w;}
};
priority_queue<Node> Q;
 
inline void add(int bg,int ed,int w){
    to[++cnt]=ed,nxt[cnt]=head[bg],val[cnt]=w,head[bg]=cnt;
}
 
int get(int x){
    if(x==F[x]) return x;
    return F[x]=get(F[x]);
}
 
inline void init(){
    tot=num=ans=cnt=0;
    for(int i=1;i<=n;i++) F[i]=i;
    memset(head,0,sizeof(head));
    memset(f,0,sizeof(f));
}
 
inline void dijkstra(){
    memset(Min,0x3f,sizeof(Min));
    Q.push(Node(1,0));Min[1]=0; Node now;
    while(Q.size()){
        now=Q.top();Q.pop();
        int x=now.id; if(Min[x]!=now.w) continue;
        for(int i=head[x];i;i=nxt[i]){
            int u=to[i];
            if(Min[x]+val[i]<Min[u]){
                Min[u]=Min[x]+val[i];
                Q.push(Node(u,Min[u]));
            }
        }
    }
}
 
inline void build(){
    for(int i=1;i<=m;i++){
        edge[i].u=rd(),edge[i].v=rd(),edge[i].l=rd(),edge[i].a=rd();
        add(edge[i].u,edge[i].v,edge[i].l); add(edge[i].v,edge[i].u,edge[i].l);
    }
    dijkstra(); sort(edge+1,edge+1+m); int x,y;
    cnt=0; memset(head,0,sizeof(head)); num=n;
    for(int i=1;i<=m;i++){
        x=get(edge[i].u); y=get(edge[i].v);
        if(x==y) continue;
        num++; F[num]=F[x]=F[y]=num;
        add(num,x,0); add(num,y,0);
        w[num]=edge[i].a; tot++;
        if(tot==n-1) break;
    }
}
 
void dfs(int x,int fa){
    f[x][0]=fa;
    for(int i=1;i<=19;i++)
        f[x][i]=f[f[x][i-1]][i-1];
    for(int i=head[x];i;i=nxt[i])
        dfs(to[i],x),Min[x]=min(Min[x],Min[to[i]]);
}
 
int query(int x,int lim){
    for(int i=19;~i;i--)
        if(f[x][i] && w[f[x][i]]>lim) x=f[x][i];
    return Min[x];
}
 
inline void work(){
    int x=rd(),y=rd();
    x=(x+ans*K%n-1+n)%n+1;
    y=(y+ans*K%(S+1))%(S+1);
    ans=query(x,y);
    printf("%lld
",ans);
}
 
int main(){
    T=rd();
    while(T--){
        n=rd(),m=rd();
        init(); build(); dfs(num,0);
        q=rd(); K=rd(); S=rd();
        while(q--) work();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/sdfzsyq/p/10275522.html