LOJ #2718. 「NOI2018」归程 Dijkstra+可持久化并查集
把 $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+可持久化并查集的更多相关文章
- loj#2718. 「NOI2018」归程
题目链接 loj#2718. 「NOI2018」归程 题解 按照高度做克鲁斯卡尔重构树 那么对于询问倍增找到当前点能到达的高度最小可行点,该点的子树就是能到达的联通快,维护子树中到1节点的最短距离 s ...
- LOJ #2718. 「NOI2018」归程(Dijkstra + Kruskal重构树 + 倍增)
题意 给你一个无向图,其中每条边有两个值 \(l, a\) 代表一条边的长度和海拔. 其中有 \(q\) 次询问(强制在线),每次询问给你两个参数 \(v, p\) ,表示在 \(v\) 出发,能开车 ...
- 洛谷 4768 LOJ 2718「NOI2018」归程
[题解] 本题有多种做法,例如可持久化并查集.kruskal重构树等. kruskal重构树的做法是这样的:先把边按照海拔h从大到小的顺序排序,然后跑kruskal建立海拔的最大生成树,顺便建krus ...
- #2718. 「NOI2018」归程 kruskal重构树
链接 https://loj.ac/problem/2718 思路 我们希望x所在的连通块尽量的大,而且尽量走高处 离线的话可以询问排序,kruskal过程中更新答案 在线就要用kruskal重构树 ...
- LOJ#2014「SCOI2016」萌萌哒(倍增,并查集优化连边)
题面 点此看题 题意很明白,就不转述了吧. 题解 题目相当于告诉了我们若干等量关系,每个限制 l 1 , r 1 , l 2 , r 2 \tt l_1,r_1,l_2,r_2 l1,r1,l2 ...
- 「NOI2018」归程
「NOI2018」归程 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 >\(1\) 个节点. \(m\) 条边的无向连通图(节点的编号从 \( ...
- LOJ #2721. 「NOI2018」屠龙勇士(set + exgcd)
题意 LOJ #2721. 「NOI2018」屠龙勇士 题解 首先假设每条龙都可以打死,每次拿到的剑攻击力为 \(ATK\) . 这个需要支持每次插入一个数,查找比一个 \(\le\) 数最大的数(或 ...
- loj#2721. 「NOI2018」屠龙勇士
题目链接 loj#2721. 「NOI2018」屠龙勇士 题解 首先可以列出线性方程组 方程组转化为在模p意义下的同余方程 因为不保证pp 互素,考虑扩展中国剩余定理合并 方程组是带系数的,我们要做的 ...
- Loj #2719. 「NOI2018」冒泡排序
Loj #2719. 「NOI2018」冒泡排序 题目描述 最近,小 S 对冒泡排序产生了浓厚的兴趣.为了问题简单,小 S 只研究对 *\(1\) 到 \(n\) 的排列*的冒泡排序. 下面是对冒泡排 ...
随机推荐
- PTA(Basic Level)1057.数零壹
给定一串长度不超过 105 的字符串,本题要求你将其中所有英文字母的序号(字母 a-z 对应序号 1-26,不分大小写)相加,得到整数 N,然后再分析一下 N 的二进制表示中有多少 0.多少 1.例如 ...
- failed to push some refs to 'git@github.com:cq1415583094/MyBatis.git'解决办法
将本地git仓库代码提交到GitHub上时,出现failed to push some refs to 'git@github.com:cq1415583094/MyBatis.git', 导致的原因 ...
- n=C(2,n)+k(构造)( Print a 1337-string)Educational Codeforces Round 70 (Rated for Div. 2)
题目链接:https://codeforc.es/contest/1202/problem/D 题意: 给你一个数 n ( <=1e9 ),让你构造137713713.....(只含有1,3,7 ...
- Bicolored RBS CodeForces - 1167D (括号)
建树, 然后高度最大值的最小值显然为$\lceil \frac{dep}{2}\rceil$, 将$>\frac{dep}{2}$的全部分出去即可. #include <sstream&g ...
- 记Tomcat进程stop卡住问题定位处理
部分内容参考自CSDN 测试环境通过agent注入了部分代码,其中包括几个Timer. 在通过启动脚本重启tomcat时,会一直有一个stop进程卡住,导致tomcat无法正常重启,进程卡住不动. 通 ...
- 给Repater增加等号
//不改变数据结构的情况下,增加行号.对Application服务器压力增大,减少DB服务器压力. protected void repShow_ItemDataBound(object sen ...
- React源码深度解析视频 某课网(完整版)
<ignore_js_op> [课程介绍]: React毫无疑问是前端界主流的框架,而框架本身就是热点.课程以讲解React实现原理为主,并在实现过程中讲解这么做的原因,带来 ...
- cassandra查询效率探讨
cassandra目前提倡的建表与查询方式为CQL方式,传统的cassandra-cli相关的api由于性能问题将逐步淘汰,而cassandra-cli也将在2.2版本之后被淘汰. 在CQL中,可以利 ...
- redis性能指标
1.当内存使用达到设置的最大阀值时,需要选择一种key的回收策略,可在Redis.conf配置文件中修改“maxmemory-policy”属性值. 若是Redis数据集中的key都设置了过期时间,那 ...
- 安装haroopad
安装haroopad 1)官网下载安装包 http://pad.haroopress.com/user.html 2)执行安装命令: sudo dpkg -i haroopad-v0.13.1-x64 ...