bzoj 5415 归程
题目描述
本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定。 魔力之都可以抽象成一个 n 个节点、m 条边的无向连通图(节点的编号从 1 至 n)。我们依次用 l,a 描述一条边的长度、海拔。 作为季风气候的代表城市,魔力之都时常有雨水相伴,因此道路积水总是不可避免 的。由于整个城市的排水系统连通,因此有积水的边一定是海拔相对最低的一些边。我们用水位线来描述降雨的程度,它的意义是:所有海拔不超过水位线的边都是有积水的。
Yazid 是一名来自魔力之都的OIer,刚参加完ION2018 的他将踏上归程,回到他 温暖的家。 Yazid 的家恰好在魔力之都的 1 号节点。对于接下来 Q 天,每一天Yazid 都会告诉你他的出发点 v ,以及当天的水位线p。 每一天,Yazid 在出发点都拥有一辆车。这辆车由于一些故障不能经过有积水的边。 Yazid 可以在任意节点下车,这样接下来他就可以步行经过有积水的边。但车会被留在他下车的节点并不会再被使用。 需要特殊说明的是,第二天车会被重置,这意味着:
- 车会在新的出发点被准备好。
- Yazid 不能利用之前在某处停放的车。 Yazid 非常讨厌在雨天步行,因此他希望在完成回家这一目标的同时,最小化他步行经过的边的总长度。请你帮助 Yazid 进行计算。 本题的部分测试点将强制在线,具体细节请见【输入格式】和【子任务】。
输入
单个测试点中包含多组数据。输入的第一行为一个非负整数T,表示数据的组数。
接下来依次描述每组数据,对于每组数据:
第一行 2 个非负整数 n,m分别表示节点数、边数。
接下来 m 行,每行 4 个正整数u, v, l, a描述一条连接节点 u, v 的、长度为 l、海拔为 a 的边。 在这里,我们保证1≤u,v≤n。
接下来一行 3 个非负数 Q, K, S ,其中 Q 表示总天数,K∈0,1 是一个会在下面被用到的系数,S 表示的是可能的最高水位线。
接下来 Q 行依次描述每天的状况。每行 2 个整数 v0;p0 描述一天:
这一天的出发节点为v=(v0+K×lastans−1)modn+1。
这一天的水位线为p=(p0+K×lastans)mod(S+1)。
其中 lastans
表示上一天的答案(最小步行总路程)。特别地,我们规定第 1 天时 lastans = 0
。 在这里,我们保证1≤v0≤n,0≤p0≤S 。
对于输入中的每一行,如果该行包含多个数,则用单个空格将它们隔开。
输出
依次输出各组数据的答案。对于每组数据:
- 输出 Q 行每行一个整数,依次表示每天的最小步行总路程。
样例输入
1 4 3 1 2 50 1 2 3 100 2 3 4 50 1 5 0 2 3 0 2 1 4 1 3 1 3 2
样例输出
0 50 200 50 150
本题就是kruskal重构树, 按照水位建立最大生成树,然后答案都在子树里面。我们要先预处理1到每个点的最短距离,注意这题卡spfa,所以要用堆优化的dijkstra。
预处理的子树的答案,然后用倍增的方法找到子树的根。
ps:我的代码在bzoj和luogu都是过的,在loj死活re是什么鬼???
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 #include<queue> 8 using namespace std; 9 int const N=200000+10; 10 int const M=400000+10; 11 int const inf=2000000000+10; 12 struct edge{ 13 int to,nt,w; 14 }e[M<<2]; 15 struct E{ 16 int x,y,z,h; 17 bool operator < (const E & rhs) const{ 18 return h>rhs.h; 19 } 20 }a[M]; 21 struct node{ 22 int v,id; 23 bool operator <(const node &rhs) const{ 24 return v>rhs.v; 25 } 26 }; 27 priority_queue<node> q; 28 int dist[N]; 29 int cnt,h1[M],h2[M],val[M],vis[N],dp[M],fa[M][20],n,m,f[M]; 30 void read(int &x){ 31 x=0; char c=getchar(); 32 while (!isdigit(c)) c=getchar(); 33 while (isdigit(c)) x=x*10+(c^48),c=getchar(); 34 } 35 void add1(int a,int b,int c){ 36 e[++cnt]=(edge){b,h1[a],c};h1[a]=cnt; 37 } 38 void add2(int a,int b){ 39 e[++cnt]=(edge){b,h2[a]}; h2[a]=cnt; 40 } 41 int find(int x){ 42 return x==f[x]? x:f[x]=find(f[x]); 43 } 44 void dijkstra(){ 45 memset(vis,0,sizeof(vis)); 46 for(int i=1;i<=n;i++) dist[i]=inf; 47 dist[1]=0;q.push((node){0,1}); 48 while (!q.empty()){ 49 int x=q.top().id; 50 q.pop(); 51 if(vis[x]) continue; 52 vis[x]=1; 53 for(int i=h1[x];i;i=e[i].nt){ 54 int v=e[i].to; 55 if(dist[x]+e[i].w<dist[v]){ 56 dist[v]=dist[x]+e[i].w; 57 if(!vis[v]) 58 q.push((node){dist[v],v}); 59 } 60 } 61 } 62 } 63 void kruscal(){ 64 sort(a+1,a+m+1); 65 for(int i=1;i<2*n;i++) f[i]=i; 66 int id=n; 67 for(int i=1;i<=m;i++){ 68 int fx=find(a[i].x); 69 int fy=find(a[i].y); 70 if(fx!=fy){ 71 id++; 72 val[id]=a[i].h; 73 f[fx]=f[fy]=id; 74 add2(id,fx); 75 add2(id,fy); 76 if (id==2*n-1) break; 77 } 78 } 79 } 80 void dfs(int x){ 81 if(x<=n) dp[x]=dist[x]; 82 else dp[x]=inf; 83 for(int i=h2[x];i;i=e[i].nt){ 84 int v=e[i].to; 85 dfs(v); 86 fa[v][0]=x; 87 dp[x]=min(dp[x],dp[v]); 88 } 89 } 90 int main(){ 91 int cas; 92 scanf("%d",&cas); 93 while (cas--){ 94 cnt=0; 95 memset(fa,0,sizeof(fa)); 96 memset(val,0,sizeof(val)); 97 memset(h1,0,sizeof(h1)); 98 memset(h2,0,sizeof(h2)); 99 scanf("%d%d",&n,&m); 100 for(int i=1;i<=m;i++){ 101 scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].z,&a[i].h); 102 add1(a[i].x,a[i].y,a[i].z); 103 add1(a[i].y,a[i].x,a[i].z); 104 } 105 dijkstra(); 106 kruscal(); 107 for(int i=2*n-1;i>=1;i--) 108 if(!fa[i][0]){ 109 fa[i][0]=i; 110 dfs(i); 111 } 112 for(int j=1;j<=19;j++) 113 for(int i=1;i<2*n;i++) 114 fa[i][j]=fa[fa[i][j-1]][j-1]; 115 int last=0,q,k,s; 116 scanf("%d%d%d",&q,&k,&s); 117 while (q--){ 118 int v,p; 119 scanf("%d%d",&v,&p); 120 v=(v+k*last-1)%n+1; 121 p=(p+k*last)% (s+1); 122 for(int i=19;i>=0;i--) 123 if(val[fa[v][i]]>p) v=fa[v][i]; 124 printf("%d\n",last=dp[v]); 125 } 126 } 127 return 0; 128 }