[NOI2018]归程

传送门

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]));
	}
}
posted @ 2019-10-15 22:19  fexuile  阅读(130)  评论(0编辑  收藏  举报