[LOJ 2718][UOJ 393][BZOJ 5415][NOI 2018]歸程

[LOJ 2718][UOJ 393][BZOJ 5415][NOI 2018]歸程

題意

給定一張無向圖, 每條邊有一個距離和一個高度. 再給定 \(q\) 組可能在線的詢問, 每組詢問給定一個點 \(v\) 和一個高度 \(h\), 鴨子德能夠先無需花費地在高度大於 \(h\) 的邊上任意行動, 而後能夠在任意點開始以花費等於距離的模式行動. 問最小的花費.php

\(|V|\le 2\times 10^5,|E|\le 4\times 10^5,q\le 4\times 10^5,h\le 10^9\).c++

題解

顯然帶花費部分的行動是一個單源最短路. 那麼咱們只要求出無花費部分的行動能夠到達的點中哪個點距離 \(1\) 最近就能夠了.git

發現無花費部分是個相似瓶頸路的問題, 咱們能夠在 Kruskal 重構樹上倍增求出能到達的點所組成的子樹, 輸出這個子樹中的點到 \(1\) 的最短距離就能夠了.spa

爲啥我要寫這個裸題的題解呢?code

一個緣由是存板子, 另外一個緣由是這個沙雕強制在線把我卡掉了 \(3\) 分qaq...具體狀況blog

參考代碼

#include <bits/stdc++.h>

const int MAXV=4e5+10;
const int MAXE=1e6+10;

struct Edge{
    int from;
    int to;
    int dis;
    int pos;
    Edge* next;
    bool friend operator>(const Edge& a,const Edge& b){
        return a.pos>b.pos;
    }
};
Edge E[MAXE];
Edge Ex[MAXE];
Edge* head[MAXV];
Edge* top=E;

int v;
int e;
int q;
int n;
int k;
int maxv;
int dis[MAXV];
int pos[MAXV];
int ufs[MAXV];
bool vis[MAXV];
int pprt[20][MAXV];
int* prt=pprt[0];

int ReadInt();
void Kruskal();
int FindRoot(int);
void Dijkstra(int);
void Insert(int,int,int,int);

int main(){
    int T=ReadInt();
    while(T--){
        memset(pprt,0,sizeof(pprt));
        memset(head,0,sizeof(head));
        memset(vis,0,sizeof(vis));
        top=E;
        n=v=ReadInt();
        e=ReadInt();
        for(int i=0;i<e;i++){
            int a=ReadInt(),b=ReadInt(),c=ReadInt(),d=ReadInt();
            Ex[i]=Edge({a,b,c,d,NULL});
            Insert(a,b,c,d);
            Insert(b,a,c,d);
        }
        q=ReadInt(),k=ReadInt(),maxv=ReadInt();
        Dijkstra(1);
        Kruskal();
        int lg=0;
        for(int i=1;(1<<i)<=v;i++){
            lg=i;
            for(int j=1;j<=v;j++)
                pprt[i][j]=pprt[i-1][pprt[i-1][j]];
        }
        int lastans=0;
        while(q--){
            int s=(0ll+ReadInt()+k*lastans-1)%n+1,h=(0ll+ReadInt()+k*lastans)%(maxv+1);
            for(int i=lg;i>=0;i--){
                if(pos[pprt[i][s]]>h)
                    s=pprt[i][s];
            }
            printf("%d\n",lastans=dis[s]);
        }
    }
    return 0;
}

void Kruskal(){
    std::sort(Ex,Ex+e,std::greater<Edge>());
    for(int i=1;i<=v;i++)
        ufs[i]=i;
    int& cur=v;
    for(int i=0;i<e;i++){
        int a=FindRoot(Ex[i].from);
        int b=FindRoot(Ex[i].to);
        if(a!=b){
            ++cur;
            pos[cur]=Ex[i].pos;
            dis[cur]=std::min(dis[a],dis[b]);
            prt[a]=cur;
            prt[b]=cur;
            ufs[cur]=cur;
            ufs[a]=cur;
            ufs[b]=cur;
        }
    }
}

void Dijkstra(int s){
    std::priority_queue<std::pair<int,int>> q;
    memset(dis,0x7F,sizeof(dis));
    dis[s]=0;
    q.emplace(0,s);
    while(!q.empty()){
        s=q.top().second;
        q.pop();
        if(vis[s])
            continue;
        vis[s]=true;
        for(Edge* i=head[s];i!=NULL;i=i->next){
            if(dis[i->to]>dis[s]+i->dis){
                dis[i->to]=dis[s]+i->dis;
                q.emplace(-dis[i->to],i->to);
            }
        }
    }
}

inline void Insert(int from,int to,int dis,int pos){
    top->from=from;
    top->to=to;
    top->dis=dis;
    top->pos=pos;
    top->next=head[from];
    head[from]=top++;
}

int FindRoot(int x){
    return ufs[x]==x?ufs[x]:ufs[x]=FindRoot(ufs[x]);
}

inline int ReadInt(){
    int x=0;
    register char ch=getchar();
    while(!isdigit(ch))
        ch=getchar();
    while(isdigit(ch)){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x;
}

相關文章
相關標籤/搜索