解法一:

  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 ;
}

解法二

[NOI2018]归程(可持久化并查集,Kruskal重构树)的更多相关文章

  1. 洛谷P4768 [NOI2018]归程 [可持久化并查集,Dijkstra]

    题目传送门 归程 格式难调,题面就不放了. 分析: 之前同步赛的时候反正就一脸懵逼,然后场场暴力大战,现在呢,还是不会$Kruskal$重构树,于是就拿可持久化并查集做. 但是之前做可持久化并查集的时 ...

  2. [NOI2018] 归程 可持久化并查集

    题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个n 个节点.m 条边的无向连通图(节点的编号从 1至 n).我们依次用 l,a描述一条边的长度.海拔. ...

  3. BZOJ5415:[NOI2018]归程(可持久化并查集,最短路)

    Description Input Output Sample Input1 14 31 2 50 12 3 100 23 4 50 15 0 23 02 14 13 13 2 Sample Outp ...

  4. UOJ 393 【NOI2018】归程——可持久化并查集

    题目:http://uoj.ac/problem/393 题解:https://www.cnblogs.com/HocRiser/p/9368067.html 但过不了 UOJ 的 hack 数据.不 ...

  5. 洛谷P4768 [NOI2018]归程(可持久化并查集,最短路)

    闲话 一个蒟蒻,在网络同步赛上进行了这样的表演-- T2组合计数不会,T3字符串数据结构不会,于是爆肝T1 一开始以为整个地图都有车,然后写了2h+的树套树,终于发现样例过不去 然后写可持久化并查集D ...

  6. NOI2018Day1T1 归程 并查集 kruskal kruskal重构树 倍增表 Dijkstra

    原文链接https://www.cnblogs.com/zhouzhendong/p/NOI2018Day1T1.html 题目传送门 - 洛谷P4768 题意 给定一个无向连通图,有 $n$ 个点 ...

  7. BZOJ5415[Noi2018]归程——kruskal重构树+倍增+堆优化dijkstra

    题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 n 个节点.m 条边的无向连通图(节点的编号从 1 至 n).我们依次用 l,a 描述一条边的长度.海 ...

  8. [学习笔记]kruskal重构树 && 并查集重构树

    Kruskal 重构树 [您有新的未分配科技点][BZOJ3545&BZOJ3551]克鲁斯卡尔重构树 kruskal是一个性质优秀的算法 加入的边是越来越劣的 科学家们借这个特点尝试搞一点事 ...

  9. [洛谷P4768] [NOI2018]归程 (kruskal重构树模板讲解)

    洛谷题目链接:[NOI2018]归程 因为题面复制过来有点炸格式,所以要看题目就点一下链接吧\(qwq\) 题意: 在一张无向图上,每一条边都有一个长度和海拔高度,小\(Y\)的家在\(1\)节点,并 ...

随机推荐

  1. c++第二十五天

    p129~p131: 1.赋值运算的左侧运算对象必须是一个可修改的左值. 2.赋值运算满足右结合律. 3.赋值运算的结果是它的左侧对象,并且是一个左值. 验证: #include<iostrea ...

  2. Python面试题目之字典排序

    按照字典的内的年龄排序 待排序的字典 d1 = [ {'name':'alice', 'age':38}, {'name':'bob', 'age':18}, {'name':'Carl', 'age ...

  3. CPA定律——一致性,可用性和分区容错性

    按照美国著名科学家 Eric Brewer 在 2000 年提出的理论,当技术架构从集中式架构向分布式架构演进,会遇到 “CAP 定律”的瓶颈. CAP 说明一个数据处理系统不能同时满足一致性,可用性 ...

  4. Owin对Asp.net Web的扩展

    类库Microsoft.Owin.Host.SystemWeb 扩展HttpContext以及HttpRequest ,新增了方法GetOwinContext // // Summary: // Pr ...

  5. fiddler几种功能强大的用法(一)

    参考网址: http://caibaojian.com/fiddler.html http://www.cnblogs.com/tangdongchu/p/4178552.html 1.fiddler ...

  6. 51Nod 1503 猪和回文

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1503 思路: 没想到要用DP去解决. 题目是从起点出发走,我们可以从起点 ...

  7. 使用yum安装pip

    PIP 简介:pip 是一个现代的,通用的 Python 包管理工具.提供了对 Python 包的查找.下载.安装.卸载的功能.功能类似于RedHat里面的yum 使用yum安装pip 因为测试环境搭 ...

  8. bzoj3223: Tyvj 1729 文艺平衡树 splay裸题

    splay区间翻转即可 /************************************************************** Problem: 3223 User: walf ...

  9. 97. Interleaving String *HARD* -- 判断s3是否为s1和s2交叉得到的字符串

    Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For example,Given:s1 = ...

  10. JS之replace

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...