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

Input

Output

Sample Input1
4 3
1 2 50 1
2 3 100 2
3 4 50 1
5 0 2
3 0
2 1
4 1
3 1
3 2
Sample Output1
50
200
50
150
Sample Input2
5 5
1 2 1 2
2 3 1 2
4 3 1 2
5 3 1 2
1 5 2 1
4 1 3
5 1
5 2
2 0
4 0
Sample Output2
HINT


Solution
会了可持久化并查集这题可能会被卡的正解就很好写了……
把边按高度大小从大到小加入,用可持久化并查集记下每一个时刻并查集的联通情况,
同时用持久化的$Min[i]$数组记录$i$点所在的连通块内到点$1$的最近距离。查询的时候二分到对应时刻的并查集直接查询就行了。
Code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#define N (200009)
using namespace std; struct Edge{int to,next,len;}edge[N<<];
struct Sgt{int ls,rs,v;};
struct Line
{
int u,v,w,h;
bool operator < (const Line &a) const {return h>a.h;}
}l[N<<];
struct Node
{
int num,dis;
bool operator < (const Node &a) const {return dis>a.dis;}
};
int T,n,m,u,v,w,h,q,k,s,v0,p0,ans;
int dis[N],head[N],num_edge;
bool vis[N];
priority_queue<Node>Q; struct Chairman_Tree
{
Sgt a[N*];
int sgt_num,b[N],Root[N<<]; int Build(int l,int r)
{
int now=++sgt_num;
if (l==r) {a[now].v=b[l]; return now;}
int mid=(l+r)>>;
a[now].ls=Build(l,mid);
a[now].rs=Build(mid+,r);
return now;
}
int Update(int pre,int l,int r,int x,int v)
{
int now=++sgt_num;
a[now].ls=a[pre].ls;
a[now].rs=a[pre].rs;
if (l==r) {a[now].v=v; return now;}
int mid=(l+r)>>;
if (x<=mid) a[now].ls=Update(a[now].ls,l,mid,x,v);
else a[now].rs=Update(a[now].rs,mid+,r,x,v);
return now;
}
int Query(int now,int l,int r,int x)
{
if (l==r) return a[now].v;
int mid=(l+r)>>;
if (x<=mid) return Query(a[now].ls,l,mid,x);
else return Query(a[now].rs,mid+,r,x);
}
}Fa,Dep,Min; inline int read()
{
int x=; char c=getchar();
while (c<'' || c>'') c=getchar();
while (c>='' && c<='') x=x*+c-'', c=getchar();
return x;
} void add(int u,int v,int w)
{
edge[++num_edge].to=v;
edge[num_edge].next=head[u];
edge[num_edge].len=w;
head[u]=num_edge;
} int Find(int x,int t)
{
int fa=Fa.Query(Fa.Root[t],,n,x);
return x==fa?x:Find(fa,t);
} void Dijkstra(int s)
{
memset(dis,0x7f,sizeof(dis));
memset(vis,,sizeof(vis));
dis[s]=;
Q.push((Node){s,});
while (!Q.empty())
{
int x=Q.top().num; Q.pop();
if (vis[x]) continue; vis[x]=;
for (int i=head[x]; i; i=edge[i].next)
if (!vis[edge[i].to] && dis[x]+edge[i].len<dis[edge[i].to])
{
dis[edge[i].to]=dis[x]+edge[i].len;
Q.push((Node){edge[i].to,dis[edge[i].to]});
}
}
} int main()
{
T=read();
while (T--)
{
Fa.sgt_num=Dep.sgt_num=Min.sgt_num=;
memset(head,,sizeof(head)); num_edge=;
ans=;
n=read(); m=read();
for (int i=; i<=m; ++i)
{
u=read(); v=read(); w=read(); h=read();
l[i]=(Line){u,v,w,h};
add(u,v,w); add(v,u,w);
}
Dijkstra();
sort(l+,l+m+);
for (int i=; i<=n; ++i)
Fa.b[i]=i, Dep.b[i]=, Min.b[i]=dis[i];
Fa.Root[]=Fa.Build(,n);;
Dep.Root[]=Dep.Build(,n);
Min.Root[]=Min.Build(,n);
for (int i=; i<=m; ++i)
{
Fa.Root[i]=Fa.Root[i-];
Dep.Root[i]=Dep.Root[i-];
Min.Root[i]=Min.Root[i-];
int fx=Find(l[i].u,i),fy=Find(l[i].v,i);
if (fx==fy) continue;
int dfx=Dep.Query(Dep.Root[i],,n,fx);
int dfy=Dep.Query(Dep.Root[i],,n,fy);
if (dfx>dfy) swap(fx,fy);
Fa.Root[i]=Fa.Update(Fa.Root[i],,n,fx,fy);
int d1=Min.Query(Min.Root[i],,n,fx);
int d2=Min.Query(Min.Root[i],,n,fy);
Min.Root[i]=Min.Update(Min.Root[i],,n,fy,min(d1,d2));
if (dfx==dfy) Dep.Root[i]=Dep.Update(Dep.Root[i],,n,fy,dfy+);
}
q=read(); k=read(); s=read();
for (int i=; i<=q; ++i)
{
v0=read(); p0=read();
v0=(v0+k*ans-)%n+;
p0=(p0+k*ans)%(s+);
int L=,R=m,A=-;
while (L<=R)
{
int mid=(L+R)>>;
if (l[mid].h>p0) A=mid,L=mid+;
else R=mid-;
}
if (A==-)
{
printf("%d\n",dis[v0]);
ans=dis[v0]; continue;
}
int fx=Find(v0,A);
ans=Min.Query(Min.Root[A],,n,fx);
printf("%d\n",ans);
}
}
}
BZOJ5415:[NOI2018]归程(可持久化并查集,最短路)的更多相关文章
- 洛谷P4768 [NOI2018]归程 [可持久化并查集,Dijkstra]
题目传送门 归程 格式难调,题面就不放了. 分析: 之前同步赛的时候反正就一脸懵逼,然后场场暴力大战,现在呢,还是不会$Kruskal$重构树,于是就拿可持久化并查集做. 但是之前做可持久化并查集的时 ...
- [NOI2018] 归程 可持久化并查集
题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个n 个节点.m 条边的无向连通图(节点的编号从 1至 n).我们依次用 l,a描述一条边的长度.海拔. ...
- [NOI2018]归程(可持久化并查集,Kruskal重构树)
解法一: 1.首先想到离线做法:将边和询问从大到小排序,并查集维护连通块以及每个连通块中所有点到1号点的最短距离.$O(n\log n)$ 配合暴力等可以拿到75分. 2.很容易想到在线做法,使用可持 ...
- UOJ 393 【NOI2018】归程——可持久化并查集
题目:http://uoj.ac/problem/393 题解:https://www.cnblogs.com/HocRiser/p/9368067.html 但过不了 UOJ 的 hack 数据.不 ...
- 洛谷P4768 [NOI2018]归程(可持久化并查集,最短路)
闲话 一个蒟蒻,在网络同步赛上进行了这样的表演-- T2组合计数不会,T3字符串数据结构不会,于是爆肝T1 一开始以为整个地图都有车,然后写了2h+的树套树,终于发现样例过不去 然后写可持久化并查集D ...
- BZOJ5415[Noi2018]归程——kruskal重构树+倍增+堆优化dijkstra
题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 n 个节点.m 条边的无向连通图(节点的编号从 1 至 n).我们依次用 l,a 描述一条边的长度.海 ...
- [bzoj3673][可持久化并查集 by zky] (rope(可持久化数组)+并查集=可持久化并查集)
Description n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0& ...
- 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集
3673: 可持久化并查集 by zky Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 1878 Solved: 846[Submit][Status ...
- bzoj3674 可持久化并查集
我是萌萌的任意门 可持久化并查集的模板题-- 做法好像很多,可以标号法,可以森林法. 本来有O(mloglogn)的神算法(按秩合并+倍增),然而我这种鶸渣就只会写O(mlog2n)的民科算法--再加 ...
随机推荐
- @Html.Raw() 与Newtonsoft.Json.JsonConvert.SerializeObject()
一.后台 ViewBag.TypeList = typeList; 二.前台C# @{ var typeListFirst = ViewBag.TypeList;} 三.前台js中 var t ...
- [日常] Go语言圣经-并发的非阻塞缓存
1.go test命令是一个按照约定和组织进行测试的程序2.竞争检查器 go run -race 附带一个运行期对共享变量访问工具的test,出现WARNING: DATA RACE 说明有数据竞争3 ...
- iOS不同网络情况调试
有时我们需要对app进行不同网络状况的测试,这时我们可以用到iPhone中的开发者功能进行测试. 按照下图所示打开网络调试功能: 可以看到系统默认配置的网络条件还 ...
- 【Linux】rpm常用命令及rpm参数介绍
RPM是RedhatPackageManager的缩写,是由RedHat公司开发的软件包安装和管理程序,同Windows平台上的Uninstaller比较类似.使用RPM,用户可以自行安装和管理Lin ...
- SWT table性能改善 -- 使用VirtualTable
在SWT程序中使用table展示数据时,如果数据过多,执行起来会比较慢,不过,我们可以借助VirtualTable来解决这一问题. Eclipse官网中关于VirtualTable的说明见:http: ...
- Android插件化
http://www.androidblog.cn/index.php/Index/detail/id/16# Android Hotfix 新方案——Amigo 源码解读 https://www.d ...
- Android - 系统开机你知道多少?
https://github.com/zhantong/interview/blob/master/Android/Android.md#38-android%E7%B3%BB%E7%BB%9F%E5 ...
- Hadoop集群动态服役新的数据节点&&退役数据节点
备注:新添的机器为hadoop05,现有hadoop01.hadoop02.hadoop03.hadoop04 环境准备: 1.先克隆一台和集群中一样的机器 2.修改机器ip和主机名称 3.删除原来的 ...
- TCP/IP 基础简介
引言本篇属于TCP/IP协议的基础知识,重点介绍了TCP/IP协议簇的内容.作用以及TCP.UDP.IP三种常见网络协议相关的基础知识. 内容TCP/IP协议簇是由OSI七层模型发展而来的,之所以存在 ...
- 解决ios10以上版本缩放问题
<script type="text/javascript"> /*解决ios10以上版本缩放问题 20171102*/ window.onload=function ...