把 $Noi2018$ day1t1 想出来还是挺开心的,虽然是一道水题~
预处理出来 1 号点到其它点的最短路,然后预处理边权从大到小排序后加入前 $i$ 个边的并查集.
这个并查集用可持久化线段树维护可持久化数组来完成.
每次询问时在边集上二分一下,找到对应的并查集,然后找到祖先并输出极小值即可.

#include <bits/stdc++.h>
#define N 400005
#define ll long long
#define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)
using namespace std;
int n,m,rt[N];
struct Edge {
int u,v,l,a;
}e[N];
bool cmp(Edge a,Edge b) {
return a.a>b.a;
}
namespace Dijkstra {
struct Node {
int u;
ll dis;
Node(int u=0,ll dis=0):u(u),dis(dis){}
bool operator<(Node a)const {
return a.dis<dis;
}
};
priority_queue<Node>q;
int edges,s;
ll dis[N];
int hd[N],nex[N<<1],val[N<<1],to[N<<1],done[N];
void addedge(int u,int v,int c) {
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;
}
void re() {
edges=0;
memset(hd,0,sizeof(hd));
memset(dis,0,sizeof(dis));
memset(done,0,sizeof(done));
}
void solve() {
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
q.push(Node(s,0));
while(!q.empty()) {
Node e=q.top();q.pop();
if(done[e.u]) continue;
done[e.u]=1;
for(int i=hd[e.u];i;i=nex[i])
if(dis[to[i]]>dis[e.u]+val[i]) {
dis[to[i]]=dis[e.u]+val[i];
q.push(Node(to[i], dis[to[i]]));
}
}
}
};
namespace ufs {
#define ls t[now].lson
#define rs t[now].rson
struct Node {
ll min;
int fa,size,lson,rson;
}t[N*50];
int tot;
void build(int &now,int l,int r) {
now=++tot;
if(l==r) {
t[now].fa=l;
t[now].size=1;
t[now].min=Dijkstra::dis[l];
return;
}
int mid=(l+r)>>1;
if(l<=mid) build(ls,l,mid);
if(r>mid) build(rs,mid+1,r);
}
void update(int pre,int &now,int l,int r,int p,Node e) {
now=++tot;
t[now]=t[pre];
if(l==r) {
t[now].size=e.size;
t[now].fa=e.fa;
t[now].min=e.min;
return;
}
int mid=(l+r)>>1;
if(p<=mid) update(t[pre].lson,t[now].lson,l,mid,p,e);
else update(t[pre].rson,t[now].rson,mid+1,r,p,e);
}
Node query(int now,int l,int r,int p) {
if(l==r) return t[now];
int mid=(l+r)>>1;
if(p<=mid) return query(ls,l,mid,p);
else return query(rs,mid+1,r,p);
}
Node find(int id,int x) {
Node p=query(rt[id],1,n,x);
return p.fa==x?p:find(id,p.fa);
}
void merge(int id,int x,int y) {
Node a=find(id,x),b=find(id,y);
if(a.fa!=b.fa) {
if(a.size<b.size) swap(a,b);
int rt1=0,rt2=0,A=a.fa,B=b.fa;
a.size+=b.size;
a.min=min(a.min,b.min);
a.fa=b.fa=A;
update(rt[id], rt1, 1, n, A, a);
update(rt1, rt2, 1, n, B, b);
rt[id+1]=rt2;
}
else rt[id+1]=rt[id];
}
void re() {
for(int i=1;i<=tot;++i) t[i].lson=t[i].rson=t[i].size=t[i].min=t[i].fa=0;
tot=0;
}
#undef ls
#undef rs
};
void work() {
int i;
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i) {
scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].l,&e[i].a);
Dijkstra::addedge(e[i].u,e[i].v,e[i].l);
Dijkstra::addedge(e[i].v,e[i].u,e[i].l);
}
Dijkstra::s=1;
Dijkstra::solve();
sort(e+1,e+1+m,cmp);
ufs::build(rt[0],1,n);
for(i=1;i<=m;++i) ufs::merge(i-1,e[i].u,e[i].v);
ll lastans=0;
int Q,K,S;
scanf("%d%d%d",&Q,&K,&S);
for(i=1;i<=Q;++i) {
int v,p;
scanf("%d%d",&v,&p);
v=(v+K*lastans-1)%n+1;
p=(p+K*lastans)%(S+1);
if(e[m].a>p) printf("0\n"),lastans=0;
else {
int l=0,r=m,mid=0,ans=0;
while(l<=r) {
mid=(l+r)>>1;
if(e[mid].a>p) {
ans=mid,l=mid+1;
}
else r=mid-1;
}
ufs::Node e=ufs::find(ans,v);
printf("%lld\n",lastans=e.min);
}
}
memset(rt,0,sizeof(rt));
Dijkstra::re();
ufs::re();
}
int main() {
// setIO("input");
int T,i;
scanf("%d",&T);
for(i=1;i<=T;++i) work();
return 0;
}

  

LOJ #2718. 「NOI2018」归程 Dijkstra+可持久化并查集的更多相关文章

  1. loj#2718. 「NOI2018」归程

    题目链接 loj#2718. 「NOI2018」归程 题解 按照高度做克鲁斯卡尔重构树 那么对于询问倍增找到当前点能到达的高度最小可行点,该点的子树就是能到达的联通快,维护子树中到1节点的最短距离 s ...

  2. LOJ #2718. 「NOI2018」归程(Dijkstra + Kruskal重构树 + 倍增)

    题意 给你一个无向图,其中每条边有两个值 \(l, a\) 代表一条边的长度和海拔. 其中有 \(q\) 次询问(强制在线),每次询问给你两个参数 \(v, p\) ,表示在 \(v\) 出发,能开车 ...

  3. 洛谷 4768 LOJ 2718「NOI2018」归程

    [题解] 本题有多种做法,例如可持久化并查集.kruskal重构树等. kruskal重构树的做法是这样的:先把边按照海拔h从大到小的顺序排序,然后跑kruskal建立海拔的最大生成树,顺便建krus ...

  4. #2718. 「NOI2018」归程 kruskal重构树

    链接 https://loj.ac/problem/2718 思路 我们希望x所在的连通块尽量的大,而且尽量走高处 离线的话可以询问排序,kruskal过程中更新答案 在线就要用kruskal重构树 ...

  5. LOJ#2014「SCOI2016」萌萌哒(倍增,并查集优化连边)

    题面 点此看题 题意很明白,就不转述了吧. 题解 题目相当于告诉了我们若干等量关系,每个限制 l 1 , r 1 , l 2 , r 2 \tt l_1,r_1,l_2,r_2 l1​,r1​,l2​ ...

  6. 「NOI2018」归程

    「NOI2018」归程 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 >\(1\) 个节点. \(m\) 条边的无向连通图(节点的编号从 \( ...

  7. LOJ #2721. 「NOI2018」屠龙勇士(set + exgcd)

    题意 LOJ #2721. 「NOI2018」屠龙勇士 题解 首先假设每条龙都可以打死,每次拿到的剑攻击力为 \(ATK\) . 这个需要支持每次插入一个数,查找比一个 \(\le\) 数最大的数(或 ...

  8. loj#2721. 「NOI2018」屠龙勇士

    题目链接 loj#2721. 「NOI2018」屠龙勇士 题解 首先可以列出线性方程组 方程组转化为在模p意义下的同余方程 因为不保证pp 互素,考虑扩展中国剩余定理合并 方程组是带系数的,我们要做的 ...

  9. Loj #2719. 「NOI2018」冒泡排序

    Loj #2719. 「NOI2018」冒泡排序 题目描述 最近,小 S 对冒泡排序产生了浓厚的兴趣.为了问题简单,小 S 只研究对 *\(1\) 到 \(n\) 的排列*的冒泡排序. 下面是对冒泡排 ...

随机推荐

  1. Postgresql 监控sql之 pg_stat_statements模块

    postgresql.confpg_stat_statements.max = 1000000pg_stat_statements.track = allpg_stat_statements.trac ...

  2. Django基础之视图(views)层、模板层

    目录 Django基础之视图(views)层.模板层 JsonResponse 向前端返回一个json格式字符串的两种方式 重写Django中的json的某个方法 form表单上传文件 FBV与CBV ...

  3. gunicorn 介绍与性能分析

    阅读此文前建议先阅读 我的博客 gunicorn 是一个 python wsgi http server,只支持在 unix 系统上运行 安装 gunicorn 其实是 python 的一个包,安装方 ...

  4. 滚动页面产生动画WOW.js的用法

    简介 在一些网页上,当你滚动页面的时候会看到各式各样的元素动画效果,非常动感.WOW.js 就是一款帮助你实现这种 CSS 动画效果的插件.WOW.js 依赖 animate.css,所以它支持 an ...

  5. Docker国内Yum源和国内镜像仓库

    Docker国内Yum源和国内镜像仓库 2018年05月29日 :: nklinsirui 阅读数 6295更多 分类专栏: Docker 版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa ...

  6. RSA 加密长度计算公式

    The length of data that can be encrypted using RSA is determined primarily by the size of the key yo ...

  7. 113、stack的优势 (Swarm20)

    参考https://www.cnblogs.com/CloudMan6/p/8157391.html   stack 将应用所包含的service,依赖的secret volume 等资源,以及他们之 ...

  8. 多Y轴,下拉框渲染,相同类型不同数据

    放上json文件: { "2017年3月": { "outKou": "5525.86", "inKou": " ...

  9. thinkphp5.1 中间件是什么,有什么用

    中间件是什么?有什么作用? 中间件主要用于拦截或过滤应用的HTTP请求,并进行必要的业务处理.---tp5.1手册 也就是说,降低了系统的耦合:[在http请求阶段,执行中间件的入口执行方法(hand ...

  10. linux上如何安装mysql

    下载rpm包: wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 安装rpm:rpm -ivh mysql-com ...