第一次参加NOI,当然,我没去现场做,只是在网络同步赛做了而已。

那网站,特别特别卡啊……

最后只交了第一题,原本认为能AC,但是因为某些原因只有50分。

我这可怜的第一次啊……

题目

题目点此处下载,密码:ghn5

思考过程

看完了所有题,就来思考第一题。

曾经的GDKOI和GDOI给我留下了不可磨灭的印象:感觉上这些题似乎都只能靠水分。

所以,我从一开始就想着打水法。

想着想着,感觉可以打个80分。好开心!

开打。

打了4000多byte,完成得差不多了,突然发现,啊,我想到正解了!!!

把这个4000多byte的程序弃掉,思考了一阵子,然后开打。

打了好久,有3000多byte,尴尬的是,过了前四个样例,却,被第五个样例卡掉了。

我好慌,好慌……

然后发现,我程序跑得慢的原因,是最短路花的时间太多了。

一世英名,卡在了最短路上。

我看看那个TLE掉的Dijsktra,不信邪,打了个SPFA。

依然被卡,于是,我决定重打一遍Dijsktra!

这一次,秒过……

然后我就愉快地交了程序……

解法

题目的意思是在图中,先走一段没有积水的路径,这些代价是免费的,然后在走到终点。

先想想该怎么搞离线的做法。

首先,肯定要求一遍最短路。

把问题转化一下,现在有积水的边不能走,你只能走没有积水的边。

答案即是你可以走到的的点中,最短路值最小的。

立体化地想一想,如果一开始没有水,然后雨越下越大,水位逐渐升高。

原本图是一个联通块,然后随着一些边的淹没,被逐渐分成了许多小的联通块。

不妨反过来想想。

可以做一遍最大生成树,维护联通块中最短路的最小值,在做的过程中统计答案。

这就是离线做法。

怎么在线呢?

维护联通块中最大值中,我用的是并查集。

既然非要在线,那就用可持久化并查集!!!

那样就可以询问历史版本,就可以在线做了,哈哈哈哈哈哈哈哈哈……

如果点x" role="presentation">xx所表示的集合要并到y" role="presentation">yy所表示的集合中时,在x" role="presentation">xx上记录一下两者联通的最高海拔。

并试着更新一下y" role="presentation">yy上维护的,表示联通块中最短路的最小值。

然而,我们需要记录一下历史版本。怎么记录?

直接暴力记录啊!反正最大生成树中,一共会连N−1" role="presentation">N−1N−1条边,那么,顶多更新N−1" role="presentation">N−1N−1次。

在每个点上存它的历史状态,直接简单粗暴的在一个数组里记录一条信息,表示某个点,在某个水位时,最短路最小值是多少。

搞完最大生成树后,排个序,然后一段区间对应的就是一个点的修改信息。

那么在询问时,先在并查集上不断往上跳,直到跳不了(再跳就被水淹没了)。

然后在这个点的修改信息中,二分出来,得出答案。

时间复杂度:

O(Nlg⁡N(Dijsktra)+(Mlg⁡M+Mlg⁡N)(最大生成树)+Nlg⁡N(排序)+Qlg⁡N(询问))=O(Mlg⁡M+(N+M+Q)lg⁡N)" role="presentation">O(NlgN(Dijsktra)+(MlgM+MlgN)(最大生成树)+NlgN(排序)+QlgN(询问))=O(MlgM+(N+M+Q)lgN)O(Nlg⁡N(Dijsktra)+(Mlg⁡M+Mlg⁡N)(最大生成树)+Nlg⁡N(排序)+Qlg⁡N(询问))=O(Mlg⁡M+(N+M+Q)lg⁡N)

代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 200000
#define MAXM 400000
int n,m;
struct edge
{
int u,v,l,a;
} ed[MAXM+1];
bool cmped(const edge &x,const edge &y)
{
return x.a>y.a;
}
struct EDGE
{
int to,l,a;
EDGE *las;
} e[MAXM*2];
int ne;
EDGE *last[MAXN+1];
void link(int u,int v,int l,int a)
{
e[ne].to=v,e[ne].l=l,e[ne].a=a;
e[ne].las=last[u];
last[u]=e+ne;
++ne;
}
long long dis[MAXN+1];
void Shortest_Path();
int Q,K,S;
struct Change_List
{
int x,a;
long long ans;
} cl[MAXN*2+1];
int ncl;
bool cmpcl(const Change_List &u,const Change_List &v)
{
return u.x<v.x || u.x==v.x && (u.a>v.a || u.a==v.a && u.ans>v.ans);
}
int ac[MAXN+1];
struct Union_Find_Set
{
int fa;
int a;
long long ans;
int dep;
} ufs[MAXN+1];
int getfa(int x)
{
while (ufs[x].fa!=x)
x=ufs[x].fa;
return x;
}
int main()
{
// freopen("return.in","r",stdin);
// freopen("return.out","w",stdout);
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
memset(last,0,sizeof last);
ne=0;
for (int i=1;i<=m;++i)
{
int u,v,l,a;
scanf("%d%d%d%d",&u,&v,&l,&a);
link(u,v,l,a);
link(v,u,l,a);
ed[i].u=u,ed[i].v=v,ed[i].l=l,ed[i].a=a;
}
scanf("%d%d%d",&Q,&K,&S);
Shortest_Path();
sort(ed+1,ed+m+1,cmped);
for (int i=1;i<=n;++i)
{
ufs[i].fa=i;
ufs[i].a=S+1;
ufs[i].ans=dis[i];
ufs[i].dep=1;
}
ncl=0;
for (int i=1;i<=n;++i)
{
++ncl;
cl[ncl].x=i;
cl[ncl].ans=dis[i];
cl[ncl].a=S+1;
}
for (int i=1;i<=m;++i)
{
int x=getfa(ed[i].u),y=getfa(ed[i].v);
if (x!=y)
{
//x->y
if (ufs[x].dep>ufs[y].dep)
swap(x,y);
ufs[x].fa=y;
ufs[x].a=ed[i].a;
ufs[y].dep=max(ufs[y].dep,ufs[x].dep+1);
if (ufs[x].ans<ufs[y].ans)
{
ufs[y].ans=ufs[x].ans;
++ncl;
cl[ncl].x=y;
cl[ncl].ans=ufs[x].ans;
cl[ncl].a=ed[i].a;
}
}
}
sort(cl+1,cl+ncl+1,cmpcl);
for (int i=1,j=0;i<=ncl;++i)
if (cl[i-1].x!=cl[i].x)
ac[j++]=i-1;
ac[n]=ncl;
long long lastans=0;
while (Q--)
{
int v,p;
scanf("%d%d",&v,&p);
v=(v+K*lastans-1)%n+1;
p=(p+K*lastans)%(S+1);
while (v!=ufs[v].fa && p<ufs[v].a)
v=ufs[v].fa;
int l=ac[v-1]+1,r=ac[v],res=-1;
while (l<=r)
{
int mid=l+r>>1;
if (p<cl[mid].a)
l=(res=mid)+1;
else
r=mid-1;
}
lastans=cl[res].ans;
printf("%lld\n",lastans);
}
}
return 0;
}
bool cmph(int son,int fa)
{
return dis[son]>dis[fa];
}
int h[MAXN],nh;
bool bz[MAXN+1];
void Shortest_Path()
{
memset(dis+1,127,sizeof(long long)*n);
memset(bz+1,0,sizeof(bool)*n);
dis[1]=0;
nh=1;
h[0]=1;
bz[1]=1;
while (nh)
{
int top=h[0];
pop_heap(h,h+nh--,cmph);
for (EDGE *ei=last[top];ei;ei=ei->las)
if (dis[top]+ei->l<dis[ei->to])
{
dis[ei->to]=dis[top]+ei->l;
if (!bz[ei->to])
{
bz[ei->to]=1;
h[nh++]=ei->to;
push_heap(h,h+nh,cmph);
}
}
bz[top]=0;
}
}

Others

1、 我比赛时没切题,是因为数组开小了……

2、 其实这个程序还有改进的地方,比如,在这题中,一些边的海拔是相同的,但我在最大生成树是会记录多条修改信息,其实可以并在一起。改起来也简单,但我懒得改了。

NOI2018 Day1 归程(return)的更多相关文章

  1. loj#2718. 「NOI2018」归程

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

  2. 【BZOJ5415】【NOI2018】归程(克鲁斯卡尔重构树)

    [NOI2018]归程(克鲁斯卡尔重构树) 题面 洛谷 题解 我在现场竟然没有把这道傻逼题给切掉,身败名裂. 因为这题就是克鲁斯卡尔重构树的模板题啊 我就直接简单的说一下把 首先发现答案就是在只经过海 ...

  3. 「NOI2018」归程

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

  4. LOJ #2718. 「NOI2018」归程 Dijkstra+可持久化并查集

    把 $Noi2018$ day1t1 想出来还是挺开心的,虽然是一道水题~ 预处理出来 1 号点到其它点的最短路,然后预处理边权从大到小排序后加入前 $i$ 个边的并查集. 这个并查集用可持久化线段树 ...

  5. 【luoguP4768】【NOI2018】归程

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

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

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

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

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

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

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

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

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

随机推荐

  1. 校园商铺-4店铺注册功能模块-5店铺注册之Service层的实现

    1. 创建接口 ShopService.java package com.csj2018.o2o.service; import java.io.File; import com.csj2018.o2 ...

  2. CSS——用户界面样式

    所谓的界面样式, 就是更改一些用户操作样式, 比如 更改用户的鼠标样式, 表单轮廓等.但是比如滚动条的样式改动受到了很多浏览器的抵制,因此我们就放弃了. 防止表单域拖拽 鼠标样式cursor 设置或检 ...

  3. Flask扩展 -- flask-mail

    电子邮件是最常用的通信方式之一.虽然Python标准库中的smtplib包可用在Flask程序中发送电子邮件,但包装了smtplib的Flask-Mail扩展能更好的和Flask集成. 1.安装Fla ...

  4. 线段树离散化+区间更新——cf1179C好题

    绝对是很好的题 把问题转化成当第i个询问的答案是数值x时是否可行 要判断值x是否可行,只要再将问题转化成a数组里>=x的值数量是否严格大于b数组里的>=x的值 那么线段树叶子结点维护对于值 ...

  5. 概率dp的迭代方式小结——zoj3329,hdu4089,hdu4035

    在推导期望方程时我们常常会遇到dp[i]和其他项有关联,那么这时候我们就难以按某个顺序进行递推 即难以通过已经确定的项来求出新的项 即未知数的相互关系是循环的 但是我们又可以确定和dp[i]相关联的项 ...

  6. 初步了解Redis

    参考: https://juejin.im/post/5b4dd82ee51d451925629622?utm_source=gold_browser_extension https://www.cn ...

  7. 怎样使用github?(转)

    怎样使用github?(转) 转自: 怎样使用 GitHub? - 知乎https://www.zhihu.com/question/20070065 珊姗是个小太阳 ❤努力做最胖//bang的健身博 ...

  8. 使用treeNMS管理及监控Redis

    Redis做为现在web应用开发的黄金搭担组合,大量的被应用,广泛用于存储session信息,权限信息,交易作业等热数据.做为一名有10年以上JAVA开发经验的程序员,工作中项目也是广泛使用了Redi ...

  9. Http学习(三)

    HTTP的问题: 通信使用明文,可能会遭到窃听:HTTP本身不具备加密功能,根据TCP/IP协议工作的线路上可能会遭到窃听,即使通信内容已经加密,也会被看到 通信加密:通过SSL(Secure Soc ...

  10. Hdu-1452-Happy 2004-费马小定理推除法逆元+同余定理+积性函数

    Consider a positive integer X,and let S be the sum of all positive integer divisors of 2004^X. Your ...