luoguP4768 [NOI2018]归程

传送门

kruskal重构树:

kruskal合并两个联通块时合并的边一定是联通块中权值最大的边,小于等于这条边的边所能联通的所有点在这个联通块中。

在合并两个联通块的时候新建一个点作为两个联通块代表点的父亲,权值为这条合并的边,那么从一个点x往上跳到最靠上的权值小于等于v的祖先,这个祖先的所有叶子节点就是从x走小于等于v的边能到达的点的集合。

所以这题以1为起点跑dijkstra找单源最短路,然后按权值从大到小排序kruskal重构树即可。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<set>
#define Formylove return 0
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
#define inf 1e18
const int N=1000007; 
typedef long long LL;
typedef double db;
using namespace std;
int T,n,m,Q,K,S;

template<typename T> void read(T &x) {
    char ch=getchar(); T f=1; x=0;
    while((ch!='-')&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

struct edge {
    int u,v,l,a;
    edge(){}
    edge(int u,int v,int a):u(u),v(v),a(a){}
    friend bool operator <(const edge&A,const edge&B) {
        return A.a>B.a;
    }
}e[N];

int ec,fir[N],nxt[N],to[N],val[N];
void add(int u,int v,int w) {
    nxt[++ec]=fir[u]; fir[u]=ec; to[ec]=v; val[ec]=w;
    nxt[++ec]=fir[v]; fir[v]=ec; to[ec]=u; val[ec]=w;
}

int fa[N];
int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); } 

int f[N][20],vv[N];

int ec2,fi[N],nx[N],tt[N];
void ADD(int u,int v) {
    nx[++ec2]=fi[u]; fi[u]=ec2; tt[ec2]=v;
}

LL fans[N],dis[N];
void dfs(int x,int F) {
    f[x][0]=F;
    fans[x]=inf;
    if(x<=n) fans[x]=dis[x];
    For(i,1,19) f[x][i]=f[f[x][i-1]][i-1];
    for(int i=fi[x];i;i=nx[i]) {
        dfs(tt[i],x);
        fans[x]=min(fans[x],fans[tt[i]]);
    }
}

int totnode;
void kruskal(int n) {
    sort(e+1,e+m+1);
    totnode=n;
    For(i,1,n*2) fa[i]=i;
    For(i,1,m) {
        int x=e[i].u,y=e[i].v;
        int fx=find(x),fy=find(y);
        if(fx!=fy) {
            totnode++;
            vv[totnode]=e[i].a;
            ADD(totnode,fx); ADD(totnode,fy);
            fa[fx]=fa[fy]=totnode;
        }
    }
    dfs(totnode,0);
}

struct node {
    int u; LL d; 
    node(int u,LL d):u(u),d(d){}
    friend bool operator <(const node&A,const node&B) {
        return A.d>B.d;
    }
};

priority_queue<node>que;
int vis[N];
void dijkstra(int s) {
    For(i,1,n) dis[i]=inf,vis[i]=0; 
    dis[s]=0; 
    que.push(node(s,0));
    while(!que.empty()) {
        node tp=que.top();
        que.pop();
        if(vis[tp.u]||dis[tp.u]!=tp.d) continue; 
        vis[tp.u]=1;
        for(int i=fir[tp.u];i;i=nxt[i]) {
            int y=to[i];
            if(dis[y]>dis[tp.u]+val[i]) {
                dis[y]=dis[tp.u]+val[i];
                que.push(node(y,dis[y])); 
            }
        } 
    } 
}

void init() {
    ec=ec2=0;
    memset(fir,0,sizeof(fir));
    memset(fi,0,sizeof(fi));
}

int main() {
#ifdef ANS
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
#endif
    read(T);
    while(T--) {
        init();
        read(n); read(m);
        For(i,1,m) {
            int u,v,l,a;
            read(u); read(v); read(l); read(a);
            add(u,v,l);
            e[i]=edge(u,v,a);
        } 
        dijkstra(1);
        kruskal(n);
        read(Q); read(K); read(S);
        LL ans=0;
        while(Q--) {
            int v0,p0;
            read(v0); read(p0);
            int x=(v0+ans%n*K%n-1)%n+1;
            int p=(p0+ans%(S+1)*K%(S+1))%(S+1);
            Rep(i,19,0) if(f[x][i]&&vv[f[x][i]]>p) 
                x=f[x][i];
            ans=fans[x];
            printf("%lld\n",ans);
        }
    } 
    Formylove;
}
View Code

 

posted @ 2018-08-28 19:49  啊宸  阅读(136)  评论(0编辑  收藏  举报