洛谷 P4768 [NOI2018]归程
361行代码的由来
数据分治大发好啊~
NOI的签到题,可怜我在家打了一下午才搞了80分。
正解应该是kruskal重构树或排序+可持久化并查集。
我就分点来讲暴力80分做法吧(毕竟正解我也没太懂)~
前6个点
这6个点有两种做法:
法1:最短路。
这6个点都是离线的,而且只有一种海拔,所以直接最短路。
跑完之后,直接判断海拔与水位,输出即可。
不过这些分也并不好拿,spfa会被卡,要用堆优化dijkstra。
法2:离线排序+并查集。
其实这个暴力思想就是正解思想了,很好想到的。
首先跑个最短路求一下1号点到所有点的距离,按照边权从大到小排序,对于询问也按照水位线从大到小排一下序。
显然,当一条边加入以后,就不可能再删除,因为水位线只会慢慢降低。
这样这个问题就可以转化成,当前询问下,如果把所有大于当前水位线的边加入图中,那么从起点出发,求它所能到达的点中与1号点距离最小的点即可。
加边时用并查集维护一下即可:
即对于两个点a,b在并查集中的祖先x,y,如果dis[x]>dis[y],则令fa[x]=y。
这样并查集在查询时,就可以以常数的复杂度找到当前询问下的答案。注意加边是在一个查询开始前,将所有海拔大于水位线的边加进去。
树和链的5个点
这里我们可以考虑倍增。
预处理3个ST表:dpt[][],num[][],xiao[][]
分别表示从x点跳\(2^j\)步,从x到向上\(2^j\)个点的花费,最后是从x到向上\(2^j\)个点中海拔最小的点。
所以算法也很简单,先调到海拔最小的点,然后再倍增求花费。
当然也可以用之前讲的离线排序+并查集。
3个离线大点
直接按上面说的离线并查集即可。
15和16两个在线小点
离线并查集不管用了?别担心。
因为数据范围小,直接在线,每次询问用一个新的并查集维护。
反正能过。
超长代码菌~
请忽略代码中的正解部分,啦啦啦~
#include <bits/stdc++.h>
using namespace std;
typedef pair<long long,int> Pair;
void read(int &aa)
{
aa=0;char c=getchar();bool f=0;
while (c>'9'||c<'0') {if (c=='-') f=1;c=getchar();}
while (c>='0'&&c<='9')
aa=(aa<<3)+(aa<<1)+(c^48),c=getchar();
(f)&&(aa=-aa);
}
const int N=800020;
int n,m,q,k,s;
struct Edge {
int next,cost,high,to;
}e[N<<2];
int last[N],spfaflag;
void add(int x,int y,int c,int h)
{
e[++last[0]].to=y;
e[last[0]].cost=c;e[last[0]].next=last[x];
e[last[0]].high=h;last[x]=last[0];
}
int vis[N];
long long dis[N];
queue <int> Q;
priority_queue< Pair,vector<Pair>,greater<Pair> >que;
void spfa()
{
while (!Q.empty()) Q.pop();
for (int i=1;i<=n;++i) dis[i]=2e9+1;
memset(vis,0,sizeof(vis));
vis[1]=1;Q.push(1);dis[1]=0;
while (!Q.empty()) {
int x=Q.front();Q.pop();vis[x]=0;
for (int i=last[x];i;i=e[i].next) {
int y=e[i].to,c=e[i].cost;
if (dis[y]>dis[x]+c) {
dis[y]=dis[x]+c;
if (!vis[y]) vis[y]=1,Q.push(y);
}
}
}
}
void dijsktra()
{
while (!que.empty()) que.pop();
for (int i=1;i<=n;++i) dis[i]=2e9+1;
memset(vis,0,sizeof(vis));
dis[1]=0;
que.push(make_pair(dis[1],1));
while (!que.empty()) {
Pair now=que.top();que.pop();
if (vis[now.second]) continue;
vis[now.second]=1;
for (int i=last[now.second];i;i=e[i].next)
if (dis[now.second]+e[i].cost<dis[e[i].to]) {
dis[e[i].to]=dis[now.second]+e[i].cost;
if (!vis[e[i].to]) que.push(make_pair(dis[e[i].to],e[i].to));
}
}
}
int bian[N],gao[N];
void chain()
{
int ed,pp,chainflag;
long long ans,preans=0;
read(q);read(k);read(s);
for (int i=1;i<=q;++i) {
chainflag=ans=0;
read(ed);read(pp);
ed=(ed+k*preans-1)%n+1;
pp=(pp+k*preans)%(s+1);
for (int t=ed;t>1;--t)
if (chainflag||gao[t]<=pp)
ans+=bian[t],chainflag=1;
printf("%lld\n",ans);
preans=ans;
}
}
int dep[N],dpt[N][33],xiao[N][33],num[N][33];
void dfs(int x,int d)
{
dep[x]=d;
for (int i=last[x];i;i=e[i].next) {
int y=e[i].to;
if (!dep[y]) {
dpt[y][0]=x;
xiao[y][0]=e[i].high;
num[y][0]=e[i].cost;
dfs(y,d+1);
}
}
}
void init()
{
for (int j=1;j<=24;++j)
for (int i=1;i<=n;++i) {
dpt[i][j]=dpt[dpt[i][j-1]][j-1];
xiao[i][j]=min(xiao[i][j-1],xiao[dpt[i][j-1]][j-1]);
num[i][j]=num[i][j-1]+num[dpt[i][j-1]][j-1];
}
}
int zuo(int x,int gaodu)
{
int ans=0;
for (int j=24;j>=0;--j) {
if (xiao[x][j]>gaodu&&dpt[x][j])
x=dpt[x][j];
}
if (x!=1) {
for (int j=24;j>=0;--j)
if (dpt[x][j])
ans+=num[x][j],x=dpt[x][j];
return ans;
}
return 0;
}
void tree()
{
int ed,pp;
dfs(1,1);init();
read(q);read(k);read(s);
int ans,preans=0;
for (int i=1;i<=q;++i) {
read(ed);read(pp);
ed=(ed+k*preans-1)%n+1;
pp=(pp+k*preans)%(s+1);ans=zuo(ed,pp);
printf("%d\n",ans);preans=ans;
}
}
struct Line {
int from,to,cost,high;
}line[N<<1];
struct ask {
int shui,id,v,res;
}wen[N];
int baba[N];
bool pai1(ask t1,ask t2)
{
return t1.shui>t2.shui;
}
bool pai2(Line t1,Line t2)
{
return t1.high>t2.high;
}
bool pai3(ask t1,ask t2)
{
return t1.id<t2.id;
}
int find(int x)
{
return x!=baba[x]?baba[x]=find(baba[x]):x;
}
void unionset(int x,int y)
{
int u=find(x),v=find(y);
if (u==v) return;
if (dis[u]>dis[v]) baba[u]=v;
else baba[v]=u;
}
void outline()
{
for (int i=1;i<=q;++i) {
read(wen[i].v);read(wen[i].shui);
wen[i].id=i;
}
sort(&wen[1],&wen[1+q],pai1);
sort(&line[1],&line[1+m],pai2);
for (int i=1;i<=n;++i) baba[i]=i;
int now=1;
for (int i=1;i<=q;++i) {
while (now<=m&&line[now].high>wen[i].shui)
unionset(line[now].from,line[now].to),++now;
wen[i].res=dis[find(wen[i].v)];
}
sort(wen+1,wen+1+q,pai3);
for (int i=1;i<=q;++i) printf("%d\n",wen[i].res);
}
void navi_inline()
{
int lastans=0,instead;
sort(line+1,line+1+m,pai2);
for (int j=1;j<=q;++j) {
for (int i=1;i<=n;++i) baba[i]=i;
int now=1;
read(instead);
int v=(instead+k*lastans-1)%n+1;
read(instead);
int p=(instead+k*lastans)%(s+1);
while (now<=m&&line[now].high>p)
unionset(line[now].from,line[now].to),++now;
lastans=dis[find(v)];
printf("%d\n",lastans);
}
}
bool cmp(Line t1,Line t2)
{
return t1.high>t2.high;
}
Line line2[N<<1];
int fa[N],ceng[N],tiao[N][25];
struct eeee {
int to,next;
}ee[N<<1];
int head[N];
void jia(int x,int y)
{
ee[++head[0]].to=y;ee[head[0]].next=head[x];
head[x]=head[0];
}
void shensou(int x,int pa)
{
ceng[x]=ceng[pa]+1,tiao[x][0]=pa;
for (int i=1;i<=24;++i)
tiao[x][i]=tiao[tiao[x][i-1]][i-1];
for (int i=head[x];i;i=ee[i].next) {
int y=ee[i].to;
shensou(y,x);
line2[x].cost=min(line2[x].cost,line2[y].cost);
}
}
int xunwenta(int x,int y)
{
for (int i=24;i>=0;--i)
if (ceng[x]-(1<<i)>0&&line2[tiao[x][i]].high>y)
x=tiao[x][i];
return line2[x].cost;
}
int find2(int x)
{
return x==fa[x]?x:fa[x]=find2(fa[x]);
}
void zhengjie_wo_wu_di_la_hahaha_kruskal()
{
int tott=0,cntt=n;
for (int i=1;i<=(n<<1);++i) fa[i]=i;
sort(line+1,line+m+1,cmp);
for (int i=1;i<=m;++i) {
int u=line[i].from,v=line[i].to;
int fx=find2(u),fy=find2(v);
if (fx!=fy) {
jia(++cntt,fx);
jia(cntt,fy);
fa[fx]=cntt;
fa[fy]=cntt;
line2[cntt].high=line[i].high;
++tott;
}
if (tott+1==n) break;
}
int lastans=0;
shensou(cntt,0);
int tttt;
while (q--) {
read(tttt);
int x=(k*lastans+tttt-1)%n+1;
read(tttt);
int y=(k*lastans+tttt)%(s+1);
printf("%d\n",lastans=xunwenta(x,y));
}
}
int main()
{
int T,x,y,c,h;read(T);
while (T--) {
memset(last,0,sizeof(last));
memset(gao,0,sizeof(gao));
memset(bian,0,sizeof(bian));
memset(dep,0,sizeof(dep));
memset(dpt,0,sizeof(dpt));
memset(xiao,0,sizeof(xiao));
memset(num,0,sizeof(num));
memset(head,0,sizeof(head));
memset(tiao,0,sizeof(tiao));
read(n);read(m);bool flag=1;
int pre=0,mp=2;
for (int i=1;i<=m;++i) {
read(x);read(y);read(c);read(h);
gao[y]=h;bian[y]=c;
if (x+1!=y) flag=0;
if (pre!=h) --mp,pre=h;
add(x,y,c,h);add(y,x,c,h);
line[i].from=x;line[i].to=y;
line[i].cost=c;line[i].high=h;
}
if (mp==1) {
int ed,pp;
read(q);read(k);read(s);dijsktra();
for (int i=1;i<=q;++i) {
spfaflag=0;
read(ed);read(pp);
ed=(ed-1)%n+1;pp=pp%(s+1);
if (pp>=pre) spfaflag=1;
printf("%lld\n",!spfaflag?dis[1]:dis[ed]);
}
continue;
}
if (m+1==n) {
if (flag) chain();
else tree();
continue;
}
read(q);read(k);read(s);
if (!k) {
dijsktra();
outline();
continue;
}
if (k&&n<=1500) {
dijsktra();
navi_inline();
continue;
}
for (int i=n+1;i<=(n<<1);++i)
line2[i].cost=0x3f3f3f3f;
dijsktra();
for (int i=1;i<=n;++i)
line2[i].cost=dis[i];
zhengjie_wo_wu_di_la_hahaha_kruskal();
}
return 0;
}
洛谷 P4768 [NOI2018]归程的更多相关文章
- [洛谷P4768] [NOI2018]归程 (kruskal重构树模板讲解)
洛谷题目链接:[NOI2018]归程 因为题面复制过来有点炸格式,所以要看题目就点一下链接吧\(qwq\) 题意: 在一张无向图上,每一条边都有一个长度和海拔高度,小\(Y\)的家在\(1\)节点,并 ...
- 洛谷P4768 [NOI2018]归程 [可持久化并查集,Dijkstra]
题目传送门 归程 格式难调,题面就不放了. 分析: 之前同步赛的时候反正就一脸懵逼,然后场场暴力大战,现在呢,还是不会$Kruskal$重构树,于是就拿可持久化并查集做. 但是之前做可持久化并查集的时 ...
- 洛谷P4768 [NOI2018]归程(Kruskal重构树)
题意 直接看题目吧,不好描述 Sol 考虑暴力做法 首先预处理出从$1$到每个节点的最短路, 对于每次询问,暴力的从这个点BFS,从能走到的点里面取$min$ 考虑如何优化,这里要用到Kruskal重 ...
- 洛谷P4768 [NOI2018]归程(可持久化并查集,最短路)
闲话 一个蒟蒻,在网络同步赛上进行了这样的表演-- T2组合计数不会,T3字符串数据结构不会,于是爆肝T1 一开始以为整个地图都有车,然后写了2h+的树套树,终于发现样例过不去 然后写可持久化并查集D ...
- 洛谷P4768 [NOI2018]归程(克鲁斯卡尔重构树+最短路)
传送门 前置技能,克鲁斯卡尔重构树 我们按道路的高度建一个最大生成树,然后建好克鲁斯卡尔重构树 那么我们需要知道一颗子树内到1点距离最近是多少(除此之外到子树内任何一个点都不需要代价) 可以一开始直接 ...
- 洛谷$P4768\ [NOI2018]$归程 $kruscal$重构树
正解:$kruscal$重构树 解题报告: 传送门$QwQ$ 语文不好选手没有人权$TT$连题目都看不懂真的要哭了$kk$ 所以先放个题目大意?就说给定一个$n$个点,$m$条边的图,每条边有长度和海 ...
- Solution -「NOI 2018」「洛谷 P4768」归程
\(\mathcal{Description}\) Link. 给定一个 \(n\) 个点 \(m\) 条边的无向连通图,边形如 \((u,v,l,a)\).每次询问给出 \(u,p\),回答 ...
- P4768 [NOI2018]归程(kruskal 重构树)
洛谷P4768 [NOI2018]归程 LOJ#2718.「NOI2018」归程 用到 kruskal 重构树,所以先说这是个啥 显然,这和 kruskal 算法有关系 (废话 这个重构树是一个有点权 ...
- Luogu P4768 [NOI2018]归程(Dijkstra+Kruskal重构树)
P4768 [NOI2018]归程 题面 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 \(n\) 个节点. \(m\) 条边的无向连通图(节点的编 ...
随机推荐
- 2014哈商大ICPC/ACM校赛解题报告
被debug邀请去參加校赛,哎,被虐..我对不起工大.. 由于本人不搞ACM,算法处于HelloWorld水准.. 虽然题目除了鸟不拉屎星人之外都非常水,但我能做到这个程度,全然是超水平发挥了.. 数 ...
- iOS开发-自动布局之autoresizingMask使用详解(Storyboard&Code)
前言:现在已经不像以前那样只有一个尺寸,现在最少的IPHONE开发需要最少需要适配三个尺寸.因此以前我们可以使用硬坐标去设定各个控件的位置,但是现在的话已经不可以了,我们需要去做适配,也许你说可以使用 ...
- Android Shape 详解
1 http://blog.csdn.net/feng88724/article/details/6398193 2 <shape xmlns:android="http://sche ...
- .net中数据缓存使用
今天 遇到一个问题 访问一个接口数据 基本上是固定的,于是想把数据 缓存下来...于是版本1 诞生了 private static ConcurrentDictionary<int, List& ...
- PyCharm 环境配置
1.去掉“自动保存功能” pycharm默认是自动保存的,习惯自己按 ctrl + s 的可以进行如下设置: 菜单File -> Settings... -> Appearance &am ...
- Web服务器性能/压力测试工具http_load、webbench、ab、Siege、loadrunner
回头看看 Web服务器性能/压力测试工具http_load.webbench.ab.Siege.loadrunner
- valgrind的编译和使用
ubuntu 平台: valgrind 3.8.1 一. 编译 ./configure --prefix=/home/frank/test/valgrind/PC/local 报错:checking ...
- JavaScript之变量、作用域和内存问题
js中的变量可能包含2种数据类型,基础数据类型和引用数据类型. 一般而言,基本数据类型是数据段,引用数据类型是对象. 保存方式的不同: 基本类型可以直接操作保存在变量中的值:而引用类型真实的值是保存在 ...
- c++ why can't class template hide its implementation in cpp file?
类似的问题还有: why can't class template use Handle Class Pattern to hide its implementation? || why there ...
- 内核交互--debugfs_转
转载:Linux内核里的DebugFS DebugFS,顾名思义,是一种用于内核调试的虚拟文件系统,内核开发者通过debugfs和用户空间交换数据.类似的虚拟文件系统还有procfs和sysfs等,这 ...