[NOI2018]归程

廉价感情. 提交于 2019-12-01 10:24:20

传送门

Luogu

Solution

首先我们可以发现,最短路和积水量没有任何的关系,所以我们可以先求出1到全图的最短路。

接下来考虑积水量怎么解决,这相当于是构造一棵最大生成树的\(Kruscal\)重构树,然后对于一个点\(q\),显然可以找到可以到达的点,这些点因为\(Kruscal\)重构树优美的性质,一定会在一个子树内,这时就可以树上倍增+线段树查询了。

Code

/*
  mail: mleautomaton@foxmail.com
  author: MLEAutoMaton
  This Code is made by MLEAutoMaton
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define REP(a,b,c) for(int a=b;a<=c;a++)
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
inline int gi(){
    int f=1,sum=0;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return f*sum;
}
const int N=800010,Inf=1e9+10;
int front[N],cnt,dis[N],vis[N],n,m,tot,fa[N],rt;
typedef pair<int,int> pii;
#define mp make_pair
vector<pii>G[N],E[N];
priority_queue<pii,vector<pii>,greater<pii> >q;
struct edge{int u,v,l,a;}edg[N];
void dijkstra(){
    q.push(mp(0,1));dis[1]=0;
    while(!q.empty()){
        int u=q.top().second;q.pop();
        if(vis[u])continue;vis[u]=1;
        for(auto now:G[u]){
            int v=now.first,w=now.second;
            if(dis[v]>dis[u]+w){
                dis[v]=dis[u]+w;q.push(mp(dis[v],v));
            }
        }
    }
}
bool cmp(edge rhs1,edge rhs2){return rhs1.a>rhs2.a;}
int find(int x){if(fa[x]!=x)fa[x]=find(fa[x]);return fa[x];}
void Add(int u,int v,int w){E[u].push_back(mp(v,w));}
void kruscal(){
    sort(edg+1,edg+m+1,cmp);
    for(int i=1;i<=n;i++)fa[i]=i;tot=n;
    for(int i=1;i<=m;i++){
        int u=find(edg[i].u),v=find(edg[i].v);
        if(u!=v){
            int t=++tot;
            Add(t,u,edg[i].a);Add(t,v,edg[i].a);
            fa[u]=fa[v]=fa[t]=t;
        }
    }
    rt=tot;
}
int f[N][22],mx[N][22],Time,dfn[N],b[N],low[N],t[N<<1];
void dfs(int u,int ff){
    f[u][0]=ff;
    dfn[u]=++Time;b[Time]=u;
    for(auto now:E[u]){
        int v=now.first,w=now.second;if(v==ff)continue;
        mx[v][0]=w;dfs(v,u);
    }
    low[u]=Time;
}
int jump(int u,int p){
    for(int i=20;~i;i--)
        if(f[u][i] && mx[u][i]>p)u=f[u][i];
    return u;
}
void build(int o,int l,int r){
    if(l==r){t[o]=dis[b[l]];return;}
    int mid=(l+r)>>1;
    build(o<<1,l,mid);build(o<<1|1,mid+1,r);
    t[o]=min(t[o<<1],t[o<<1|1]);
}
int query(int o,int l,int r,int posl,int posr){
    if(posl<=l && r<=posr)return t[o];
    int mid=(l+r)>>1,ret=Inf;
    if(posl<=mid)ret=min(ret,query(o<<1,l,mid,posl,posr));
    if(mid<posr)ret=min(ret,query(o<<1|1,mid+1,r,posl,posr));
    return ret;
}
void solve();
int main(){
    int T=gi();
    while(T--)solve();
    return 0;
}
void solve(){
    memset(front,0,sizeof(front));cnt=0;Time=0;
    memset(dis,63,sizeof(dis));memset(vis,0,sizeof(vis));
    n=gi();m=gi();
    for(int i=1;i<=n;i++)G[i].clear();
    for(int i=1;i<=tot;i++)E[i].clear();
    for(int i=1;i<=m;i++){
        edg[i].u=gi(),edg[i].v=gi(),edg[i].l=gi(),edg[i].a=gi();
        G[edg[i].u].push_back(mp(edg[i].v,edg[i].l));
        G[edg[i].v].push_back(mp(edg[i].u,edg[i].l));
    }
    dijkstra();kruscal();
    dfs(rt,rt);build(1,1,tot);f[rt][0]=0;
    for(int j=1;j<=20;j++)
        for(int i=1;i<=tot;i++){
            f[i][j]=f[f[i][j-1]][j-1];
            mx[i][j]=min(mx[i][j-1],mx[f[i][j-1]][j-1]);
        }
    int Q=gi(),K=gi(),S=gi(),lastans=0;
    while(Q--){
        int v=(gi()+1ll*K*lastans%n-1)%n+1,p=(gi()+1ll*K*lastans%(S+1))%(S+1);
        v=jump(v,p);
        printf("%d\n",lastans=query(1,1,tot,dfn[v],low[v]));
    }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!