zz:https://blog.csdn.net/dreaming__ldx/article/details/81106748

以海拔为第一关键字对边进行从大到小的排序,然后修建kruskal重构树,这样就弄出了一颗以海拔为关键字的小根堆。然后对于每一棵子树,如果询问中的水位线是低于子树的根节点的,那么此时这棵子树中的所有叶子结点都是连通的。放到题中就是说这颗子树中任选一个点出发,到子树中的其它点都不需要花费。则它到1的实际开支为这些点中到1的最短路的最小值,这个最小值是在不考虑海平线的前提下,尽量走最短路径的权值。

然后我们假设对于当前询问,我们找到了一个子树的根节点u,满足d[u]>p且d[fa[u]]<=p (d[i]代表i点海拔)且出发点v在子树中,这时从v出发可以直接抵达子树中的任意一个叶子结点。因此我们需要从众多叶子节点(即原图给的点)中选出一个距离1号点花费最小的。时间复杂度O(T*N*LogN)
算法流程如下:
我们首先要求出每个点到1号点的最小花费,这个直接dijstra+最短路预处理。然后是要建出kruskal重构树,再然后维护以每个点作为根节点时子树中距离1号点的最小花费,这个建完树后一个简单的dfs搞定。最后是如何找到点u,这时我们要让一个重要的算法登场:倍增算法。直接加上点权>p的限制在树上倍增即可。

#include<bits/stdc++.h>
#define N 400005
#define M 800005
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
inline void write(int x)
{
if(x>9)write(x/10);
putchar(x%10+'0');
}
int n,m,T,q,k,s,vis[N],first[N<<1],head[N],cntx=0,d[N],dep[N],f[N][20],fa[N<<1],lastans=0,totx=0;
struct Node、
{
int u,v,l,a;
}e[M],p[N<<1];
struct edge
{
int v,next;
}tr[M<<1];
struct node
{
int v,next,w;
}t[M];
struct heap
{
int u,v;
};
inline bool operator<(heap a,heap b){return a.v>b.v;}
inline void dijstra(int s=1) //找出每个点到s的最短路
{
memset(vis,false,sizeof(vis));
memset(d,0x3f,sizeof(d));
priority_queue<heap>q;
d[s]=0;
q.push((heap){s,d[s]});
while(!q.empty()){
heap x=q.top();
q.pop();
if(vis[x.u])continue;
vis[x.u]=true;
for(int i=head[x.u];i;i=t[i].next){
int v=t[i].v;
if(vis[v])continue;
if(d[v]>d[x.u]+t[i].w){
d[v]=d[x.u]+t[i].w
;
q.push((heap){v,d[v]});
}
}
}
for(int i=1;i<=n;++i)
p[i].l=d[i];//结果放到p[i].l中
}
inline bool cmp(Node a,Node b)
{
return a.a>b.a;
}
inline int find(int x)
{
return x==fa[x]?fa[x]:fa[x]=find(fa[x]);
}
inline void add(int u,int v)//重构树是用来连边的
{
tr[++cntx].v=v;
tr[cntx].next=first[u];
first[u]=cntx;
}
inline void addx(int u,int v,int w)//原图连边用的,带权
{
t[++totx].v=v;
t[totx].next=head[u];
t[totx].w=w;
head[u]=totx;
}
inline void dfs(int u,int pa)
{
dep[u]=dep[pa]+1,f[u][0]=pa;
for(int i=1;i<=19;++i)f[u][i]=f[f[u][i-1]][i-1];
for(int i=first[u];i;i=tr[i].next)
{
int v=tr[i].v;
dfs(v,u);
p[u].l=min(p[u].l,p[v].l);
//u,v是相连的,也就是说如果这边的海拔线高于规定的话,则从u,v之间可以直达
//于是要选两者的最小值
//u要么与两个叶子点相连,要么与一个叶子点一个新增点相连
//最终u为以u为根的子树中,所有点到1的最短路
//也就是说如果能走到u点,则此时p[u].l就是其子树中某个点到1的最短路
}
}
inline int query(int x,int y)
{
for(int i=19;i>=0;--i)
if(dep[x]-(1<<i)>0&&p[f[x][i]].a>y)
//一直向上跳,只要所跳的点海拔高于规定值. 注意是高于,不是高于等于
x=f[x][i];
return p[x].l;
}
inline void kruskal()
{
int tot=0,cnt=n;
for(int i=1;i<=(n<<1);++i)
fa[i]=i;
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;++i)
{
int u=e[i].u,v=e[i].v;
int fx=find(u),fy=find(v);
if(fx!=fy){
add(++cnt,fx);
add(cnt,fy);
fa[fx]=cnt;
fa[fy]=cnt;
p[cnt].a=e[i].a;
++tot;
}
if(tot==n-1)break;
}
dfs(cnt,0);
while(q--)
{
int x=(k*lastans+read()-1)%n+1,y=(k*lastans+read())%(s+1);
write(lastans=query(x,y));
puts("");
}
}
int main(){
T=read();
while(T--){
lastans=0,n=read(),m=read();
memset(e,0,sizeof(e)),cntx=0,totx=0;
memset(first,0,sizeof(first));
memset(head,0,sizeof(head));
memset(f,0,sizeof(f));
for(int i=1;i<=m;++i)
e[i].u=read(),e[i].v=read(),e[i].l=read(),
e[i].a=read(),addx(e[i].u,e[i].v,e[i].l),addx(e[i].v,e[i].u,e[i].l);
for(int i=n+1;i<=(n<<1);++i) //注意是2*n个点,因为要新增n-1个点
p[i].l=0x3f3f3f3f;
dijstra();
q=read(),k=read(),s=read();
kruskal();
}
return 0;
}

  

Noi2018 归途的更多相关文章

  1. 关于NOIP2016与NOI2018

    NOIP2016惨淡收场了,距离省一还有相当一大段距离,省队更是差了十条街去了,不过没关系. 既然已经对信息学产生了兴趣,竞赛无疑是最好的锻炼场所. 路是自己选择的,伤痕累累也要走下去. 还有一年,事 ...

  2. 【NOI2018模拟5】三角剖分Bsh

    [NOI2018模拟5]三角剖分Bsh Description 给定一个正 n 边形及其三角剖分,共 2n - 3 条边 (n条多边形的边和n-3 条对角线),每条边的长度为 1. 共 q 次询问,每 ...

  3. JZOJ 5602.【NOI2018模拟3.26】Cti

    JZOJ 5602.[NOI2018模拟3.26]Cti Description 有一个 \(n×m\) 的地图,地图上的每一个位置可以是空地,炮塔或是敌人.你需要操纵炮塔消灭敌人. 对于每个炮塔都有 ...

  4. 【NOI2018模拟】Yja

    [NOI2018模拟]Yja Description 在平面上找\(n\)个点,要求这 \(n\)个点离原点的距离分别为 \(r1,r2,...,rn\) .最大化这\(n\) 个点构成的凸包面积,凸 ...

  5. BZOJ5418[Noi2018]屠龙勇士——exgcd+扩展CRT+set

    题目链接: [Noi2018]屠龙勇士 题目大意:有$n$条龙和初始$m$个武器,每个武器有一个攻击力$t_{i}$,每条龙有一个初始血量$a_{i}$和一个回复值$p_{i}$(即只要血量为负数就一 ...

  6. BZOJ5417[Noi2018]你的名字——后缀自动机+线段树合并

    题目链接: [Noi2018]你的名字 题目大意:给出一个字符串$S$及$q$次询问,每次询问一个字符串$T$有多少本质不同的子串不是$S[l,r]$的子串($S[l,r]$表示$S$串的第$l$个字 ...

  7. BZOJ5419[Noi2018]情报中心——线段树合并+虚树+树形DP

    题目链接: [NOI2018]情报中心 题目大意:给出一棵n个节点的树,边有非负边权,并给出m条链,对于每条链有一个代价,要求选出两条有公共边的链使两条链的并的边权和-两条链的代价和最大. 花了一天的 ...

  8. 【BZOJ5417】[NOI2018]你的名字(线段树,后缀自动机)

    [BZOJ5417][NOI2018]你的名字(线段树,后缀自动机) 题面 BZOJ 洛谷 题解 首先考虑\(l=1,r=|S|\)的做法,对于每次询问的\(T\)串,暴力在\(S\)串的\(SAM\ ...

  9. 【BZOJ5416】【NOI2018】冒泡排序(动态规划)

    [BZOJ5416][NOI2018]冒泡排序(动态规划) 题面 BZOJ 洛谷 UOJ 题解 考场推出了就是两个上升子序列,并且最长下降子序列长度不超过\(2\)...然后大力暴力状压\(dp\)混 ...

随机推荐

  1. STM32程序加载与调试

    1.STM32程序的ISP下载,只能使用串口1,其它串口不可以.

  2. pandas的数据统计函数

    # 1汇总类统计 # 2唯一去重和按值计数 # 3 相关系数和协方差 import pandas as pd # 0 读取csv数据 df = pd.read_csv("beijing_ti ...

  3. JAVA(-Xms,Xmx,Xmn-XX:newSize,-XX:MaxnewSize,-XX:PermSize,-XX:MaxPermSize)区别

    1.-Xms:表示java虚拟机堆区内存初始内存分配的大小,通常为操作系统可用内存的1/64大小即可,但仍需按照实际情况进行分配.2.-Xmx:表示java虚拟机堆区内存可被分配的最大上限,通常为操作 ...

  4. flask项目中设置logo

    <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}&qu ...

  5. 【NOIP2016提高A组8.11】自然数

    题目 分析 \(O(n)\)求出mex(1,i)(1<=i<=n): 虽然0<=ai<=10^9,但只有n个数,所以mex一定小于等于n for(long long j=1;j ...

  6. 【bzoj4552】【Tjoi2016&Heoi2016】【NOIP2016模拟7.12】排序

    题目 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次 ...

  7. LeetCode--008--字符串转换整数 (atoi)(python)

    示例 1: 输入: "42"输出: 42示例 2: 输入: " -42"输出: -42解释: 第一个非空白字符为 '-', 它是一个负号.  我们尽可能将负号与 ...

  8. pytest-生成测试报告

    import pytest """ 使用pytest编写用例,必须遵守以下规则: (1)测试文件名必须以"test_"开头或者"_test& ...

  9. LTE系统时延及降低空口时延的4种方案

    转载:https://rf.eefocus.com/article/id-LTE%20delay 对于移动通信业务而言,最重要的时延是端到端时延, 即对于已经建立连接的收发两端,数据包从发送端产生,到 ...

  10. mysql UNIQUE约束 语法

    mysql UNIQUE约束 语法 作用:UNIQUE 约束唯一标识数据库表中的每条记录. 江苏大理石平台 说明:UNIQUE 和 PRIMARY KEY 约束均为列或列集合提供了唯一性的保证.PRI ...