解法一:

  1.首先想到离线做法:将边和询问从大到小排序,并查集维护连通块以及每个连通块中所有点到1号点的最短距离。$O(n\log n)$

  配合暴力等可以拿到75分。

  2.很容易想到在线做法,使用可持久化并查集,询问时二分即可。

  不能使用路径压缩,应该按秩合并,注意秩是树的深度而不是大小。$O((E+Q)\log^2 N)$

  由于常数过大,基本过不去。

  3.考虑优化算法二,发现访问历史版本并不需要修改而只需要询问,所以一开始只使用普通的并查集,用可持久化数组记录并查集的修改情况。

  $O((N+E)\log N+Q\log^2 N)$,卡时通过。

  4.算法三的复杂度已经难以优化,考虑优化常数。不需要可持久化数据结构,直接对并查集的每个点用vector存下修改情况,询问时二分即可。

  $O(n\log^2 n)$,常数很小,轻松通过。

解法二:

  考虑Kruskal重构树,对海拔跑一次Kruskal同时对每条边新建一个节点,权值为边的海拔,并对每个点存下重构树的子树中到1号点的最小值。

  问题实际上是求一个点能通过走海拔不低于某个值的边到达的点中离1好号点最近的距离,也就是重构树上点权大于某个值的节点的子树中到1号点的最小值。倍增查询即可。

 #include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
using namespace std; const int N=,inf=;
bool b[N];
int n,m,T,q,K,S,v,p,cnt,Ans,mn[N],fa[N],ans[N],to[N],nxt[N],dis[N],val[N],h[N];
struct E{ int u,v,l,a; }e[N];
struct Que{ int v,p,id; }que[N];
struct P{ int x,d; };
bool operator <(const P &a,const P &b){ return a.d>b.d; }
priority_queue<P>Q; void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
int get(int x){ return (fa[x]==x) ? x : fa[x]=get(fa[x]); } bool cmp(E a,E b){ return a.a>b.a; }
bool cmp1(Que a,Que b){ return a.p>b.p; } void Dij(){
rep(i,,n) dis[i]=inf,b[i]=; dis[]=;
Q.push((P){,});
while (!Q.empty()){
int x=Q.top().x; Q.pop();
if (b[x]) continue;
b[x]=;
for (int i=h[x],k; i; i=nxt[i])
if (!b[k=to[i]] && dis[k]>dis[x]+val[i])
Q.push((P){k,dis[k]=dis[x]+val[i]});
}
} int main(){
freopen("return.in","r",stdin);
freopen("return.out","w",stdout);
for (scanf("%d",&T); T--; ){
scanf("%d%d",&n,&m);
rep(i,,n) h[i]=; cnt=; Ans=;
rep(i,,m){
scanf("%d %d %d %d",&e[i].u,&e[i].v,&e[i].l,&e[i].a);
add(e[i].u,e[i].v,e[i].l); add(e[i].v,e[i].u,e[i].l);
}
sort(e+,e+m+,cmp); Dij();
scanf("%d%d%d",&q,&K,&S);
if (K){
rep(i,,q){
rep(i,,n) mn[i]=dis[i],fa[i]=i;
scanf("%d%d",&v,&p);
v=(v+K*Ans-)%n+; p=(p+K*Ans)%(S+); int st=;
while (e[st].a>p && st<=m){
int u=get(e[st].u),v=get(e[st].v);
if (u!=v){ fa[u]=v; mn[v]=min(mn[v],mn[u]); }
st++;
}
printf("%d\n",Ans=mn[get(v)]);
}
continue;
}
rep(i,,q) scanf("%d%d",&que[i].v,&que[i].p),que[i].id=i;
sort(que+,que+q+,cmp1); int st=;
rep(i,,n) mn[i]=dis[i],fa[i]=i;
rep(i,,q){
while (e[st].a>que[i].p && st<=m){
int u=get(e[st].u),v=get(e[st].v);
if (u!=v){ fa[u]=v; mn[v]=min(mn[v],mn[u]); }
st++;
}
ans[que[i].id]=mn[get(que[i].v)];
}
rep(i,,q) printf("%d\n",ans[i]);
}
return ;
}

75分

 #include<queue>
#include<cstdio>
#include<vector>
#include<algorithm>
#define pb push_back
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
using namespace std; const int N=,inf=;
bool b[N];
int n,m,q,k,s,T,ans,cnt,dis[N],fa[N],mn[N],h[N],dep[N],to[N<<],val[N<<],nxt[N<<];
struct E{ int u,v,l,a; }e[N];
struct S{ int p,v; };
struct P{ int x,d; };
bool operator <(const E &a,const E &b){ return a.a>b.a; }
bool operator <(const P &a,const P &b){ return a.d>b.d; }
bool operator <(const S &a,const S &b){ return a.p>b.p; }
vector<S>Fa[N],Mn[N];
priority_queue<P>Q; void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
int find(int x){ return (x==fa[x]) ? x : find(fa[x]); } void Dij(){
rep(i,,n) dis[i]=inf,b[i]=; dis[]=; Q.push((P){,});
while (!Q.empty()){
int x=Q.top().x; Q.pop();
if (b[x]) continue;
b[x]=;
for (int i=h[x],k; i; i=nxt[i])
if (!b[k=to[i]] && dis[k]>dis[x]+val[i])
Q.push((P){k,dis[k]=dis[x]+val[i]});
}
} void init(){
cnt=; while (!Q.empty()) Q.pop();
rep(i,,n) h[i]=,Fa[i].clear(),Mn[i].clear();
} void work(){
scanf("%d%d",&n,&m);
rep(i,,m){
scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].l,&e[i].a);
add(e[i].u,e[i].v,e[i].l); add(e[i].v,e[i].u,e[i].l);
}
Dij(); sort(e+,e+m+);
rep(i,,n) Fa[i].pb((S){inf,fa[i]=i}),Mn[i].pb((S){inf,mn[i]=dis[i]}),dep[i]=;
rep(i,,m){
int p=e[i].a,u=find(e[i].u),v=find(e[i].v);
if (u==v) continue;
if (dep[u]>dep[v]) swap(u,v);
fa[u]=v; dep[v]=max(dep[u]+,dep[v]); mn[v]=min(mn[v],mn[u]);
Fa[u].pb((S){p,fa[u]}); Mn[v].pb((S){p,mn[v]});
}
scanf("%d%d%d",&q,&k,&s); ans=;
rep(i,,q){
int v,p; scanf("%d%d",&v,&p); v=(v+k*ans-)%n+; p=(p+k*ans)%(s+);
for (int f; v!=(f=(--lower_bound(Fa[v].begin(),Fa[v].end(),(S){p,}))->v); v=f);
printf("%d\n",ans=(--lower_bound(Mn[v].begin(),Mn[v].end(),(S){p,}))->v);
}
} int main(){
freopen("return.in","r",stdin);
freopen("return.out","w",stdout);
for (scanf("%d",&T); T--; ) init(),work();
return ;
}

解法一

 #include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
using namespace std; const int N=,inf=;
bool b[N];
int n,m,q,K,v,p,S,T,ans,tot,cnt,dis[N],fa[N],s[N],mn[N],h[N],Fa[N][],to[N<<],val[N<<],nxt[N<<];
struct E{ int u,v,l,a; }e[N];
struct P{ int x,d; };
bool operator <(const P &a,const P &b){ return a.d>b.d; }
bool operator <(const E &a,const E &b){ return a.a>b.a; }
priority_queue<P>Q; void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
int find(int x){ return (x==fa[x]) ? x : fa[x]=find(fa[x]); } void Dij(){
rep(i,,n) dis[i]=inf,b[i]=; dis[]=; Q.push((P){,});
while (!Q.empty()){
int x=Q.top().x; Q.pop();
if (b[x]) continue;
b[x]=;
for (int i=h[x],k; i; i=nxt[i])
if (!b[k=to[i]] && dis[k]>dis[x]+val[i])
Q.push((P){k,dis[k]=dis[x]+val[i]});
}
} void dfs(int x){
if (x>n) mn[x]=inf; else mn[x]=dis[x];
for (int i=h[x],k; i; i=nxt[i])
Fa[k=to[i]][]=x,dfs(k),mn[x]=min(mn[x],mn[k]);
} void Kruskal(){
rep(i,,n) h[i]=; cnt=; tot=n;
rep(i,,n) fa[i]=i;
rep(i,,m){
int u=find(e[i].u),v=find(e[i].v);
if (u==v) continue;
s[++tot]=e[i].a; fa[u]=fa[v]=fa[tot]=tot;
add(tot,u,); add(tot,v,);
}
dfs(tot);
} void work(){
scanf("%d%d",&n,&m);
rep(i,,m){
scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].l,&e[i].a);
add(e[i].u,e[i].v,e[i].l); add(e[i].v,e[i].u,e[i].l);
}
Dij(); sort(e+,e+m+); Kruskal();
rep(i,,) rep(x,,tot) Fa[x][i]=Fa[Fa[x][i-]][i-];
scanf("%d%d%d",&q,&K,&S); ans=;
while (q--){
scanf("%d%d",&v,&p);
v=(v+K*ans-)%n+; p=(p+K*ans)%(S+);
for (int i=; ~i; i--) if (Fa[v][i] && s[Fa[v][i]]>p) v=Fa[v][i];
printf("%d\n",ans=mn[v]);
}
} void init(){ cnt=; memset(Fa,,sizeof(Fa)); memset(h,,sizeof(h)); } int main(){
freopen("return.in","r",stdin);
freopen("return.out","w",stdout);
for (scanf("%d",&T); T--; ) init(),work();
return ;
}

解法二

最新文章

  1. HDU5456 Matches Puzzle Game(DP)
  2. JAVA基础,字符串
  3. golang笔记——流程控制
  4. Google翻译请求(难点是tk参数)
  5. SQL触发器中若取到null值可能引发的问题
  6. 在Asp.Net MVC中PartialView与EditorFor和DisplayFor的区别
  7. 在ubuntu14.04上配置cuda_caffe_cudnn_anaconda_digits
  8. CSS2系列:BFC(块级格式化上下文)IFC(行级格式化上下文)
  9. Bluetooth GATT介绍
  10. 通过PowerShell查看Android端log信息
  11. JSON 和 JSONP
  12. 【高德地图API】从零开始学高德JS API(一)地图展现——仙剑地图,麻点图,街景,室内图
  13. 如何用程序删除win 7下SYSTEM权限的目录
  14. PTA中提交Python3程序的一些套路
  15. Socket层实现系列 — getsockname()和getpeername()的实现
  16. 支持向量机(Support Vector Machine,SVM)—— 线性SVM
  17. 第14月第11天 linkmap
  18. 测试开发之Django——No1.介绍以及引申
  19. HDU4609:3-idiots(FFT)
  20. 【转载】C#堆和栈的区别

热门文章

  1. sqoop2-1.99.5-cdh5.5.4.tar.gz的部署搭建
  2. pyDay16
  3. INNODB锁(2)
  4. Activiti工作流引擎简介
  5. RC522 模块驱动程序
  6. XML_CPP_ZC_libXml2
  7. DWZ 框架详解
  8. jq对象和DOM对象的互换
  9. window下rabbitmq环境安装
  10. HDU 4842 距离压缩DP