【题解】

  本题有多种做法,例如可持久化并查集、kruskal重构树等。

  kruskal重构树的做法是这样的:先把边按照海拔h从大到小的顺序排序,然后跑kruskal建立海拔的最大生成树,顺便建kruskal重构树。

  这样建出来的重构树是一个小根堆,也就是说,如果某个节点没有被淹,它的子树内的点都不会被淹,它们可以互相开车到达。

  我们建重构树的时候维护每个节点的子树内的点到1号点的最小距离mn,mn先用dijkstra处理好。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define rg register
#define N 400010
using namespace std;
int T,n,m,q,k,s,tot,cnt,last[N],f[N],pos[N],p[N][],hei[N];
LL ans,mn[N];
struct edge{
int to,pre,dis;
}e[N<<];
struct rec{
int u,v,h;
}r[N<<];
struct heap{
LL d;int p;
}h[N];
inline int read(){
int k=,f=; char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(''<=c&&c<='')k=k*+c-'',c=getchar();
return k*f;
}
inline void up(int x){
int fa;
while((fa=(x>>))&&h[fa].d>h[x].d) swap(h[x],h[fa]),swap(pos[h[x].p],pos[h[fa].p]),x=fa;
}
inline void down(int x){
int son;
while((son=(x<<))<=tot){
if(son<tot&&h[son].d>h[son+].d) son++;
if(h[son].d<h[x].d) swap(h[x],h[son]),swap(pos[h[x].p],pos[h[son].p]),x=son;
else return;
}
}
inline void dijkstra(int x){
for(rg int i=;i<=(n<<);i++) mn[i]=4e9;
h[tot=pos[x]=]=(heap){mn[x]=,x};
while(tot){
int now=h[].p; pos[h[tot].p]=; h[]=h[tot--]; if(tot) down();
for(rg int i=last[now],to;i;i=e[i].pre)
if(mn[to=e[i].to]>mn[now]+e[i].dis){
mn[to]=mn[now]+e[i].dis;
if(!pos[to]) h[pos[to]=++tot]=(heap){mn[to],to};
else h[pos[to]].d=mn[to];
up(pos[to]);
}
}
}
inline int climb(int x,int y){
for(rg int i=;i>=;i--) if(hei[p[x][i]]>y) x=p[x][i]; return x;
}
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
inline bool cmp(rec a,rec b){return a.h>b.h;}
inline void Pre(){
tot=; cnt=; ans=;
memset(last,,sizeof(last));
memset(pos,,sizeof(pos));
memset(p,,sizeof(p));
}
int main(){
freopen("return.in","r",stdin);
freopen("return.out","w",stdout);
T=read();
while(T--){
Pre();
n=read(); m=read();
for(rg int i=;i<=m;i++){
int u,v,d;
r[i].u=u=read(),r[i].v=v=read(),d=read(),r[i].h=read();
e[++tot]=(edge){v,last[u],d}; last[u]=tot;
e[++tot]=(edge){u,last[v],d}; last[v]=tot;
}
dijkstra();
// for(rg int i=1;i<=n;i++) printf("%d ",mn[i]); puts("mn");
tot=n;
sort(r+,r++m,cmp);
for(rg int i=;i<=n;i++) f[i]=i,f[i+n]=i+n;
for(rg int i=;i<=m;i++){
int u=find(r[i].u),v=find(r[i].v);
if(u!=v){
hei[++tot]=r[i].h; mn[tot]=min(mn[u],mn[v]);
f[u]=f[v]=p[u][]=p[v][]=tot;
cnt++;
}
if(cnt==n-) break;
}
for(rg int j=;j<;j++)
for(rg int i=;i<=tot;i++) p[i][j]=p[p[i][j-]][j-]; q=read(); k=read(); s=read();
while(q--){
int v0=(read()+k*ans-)%n+,p0=(read()+k*ans)%(s+);
// printf("v0=%d p0=%d\n",v0,p0);
printf("%lld\n",ans=mn[climb(v0,p0)]);
}
}
return ;
}

  那么对于每个出发点为v的询问,我们倍增找到它最早的不被淹的祖先p,答案就是mn[p].

最新文章

  1. MQL4程序:一个号称成功率100%的EA程序 .mq4
  2. Guava学习笔记:Guava新增集合类型-Bimap
  3. linxu scp命令
  4. 静态修饰符(关键字static)
  5. 用puthivestreaming把hdfs里的数据流到hive表
  6. 获得输入框的文本document.getElementById(&#39;id&#39;).value;
  7. java final
  8. UVA 10537 The Toll! Revisited uva1027 Toll(最短路+数学坑)
  9. SharePoint 2013 入门教程--系列文章
  10. java_jdbc_反射技术将查询结果封装为对象
  11. *max_element函数和*min_element函数
  12. bug记录_document.defaultview.getcomputedstyle()
  13. Codeforces Round #410 (Div. 2)C题
  14. 简洁灵活的前端框架------BootStrap
  15. HDU1754 I hate it(线段树 单点修改)
  16. Hdoj 1003.Max Sum 题解
  17. ASP.NET MVC5高级编程 之 HTML辅助方法
  18. 3星|《AI极简经济学》:AI的预测、决策、战略等方面的应用案例介绍
  19. 指定某个div随着指定大div滚动,而不是随着整个窗口固定不动
  20. js中将斜杠\替换的方法

热门文章

  1. query或者JavaScript实现在textarea光标处插入文本
  2. HTML5来了,7个混合式移动开发框架
  3. jQuery setInterval倒计时精确到毫秒
  4. 用SpringMVC实现的上传下载
  5. 235 Lowest Common Ancestor of a Binary Search Tree 二叉搜索树的最近公共祖先
  6. C#基础 特殊集合
  7. nginx connect failed (110- Connection timed out) 问题排查
  8. js实现浮动框跟随页面滚动,最后停留在原来位置
  9. C++学习笔记(二)之数组
  10. php redis 操作大全