【CSP模拟赛】避难向导(倍增lca&树的直径)
耐力OIer,一天7篇博客
题目描述
“特大新闻,特大新闻!全国爆发了一种极其可怕的病毒,已经开始在各个城市 中传播开来!全国陷入了巨大的危机!大量居民陷入恐慌,想要逃到其它城市以 避难!经调查显示,该病毒来自于C 市的A 学校的一次非法的……” “哎。”你关上电视,叹了口气。作为A 学校的校长,你一天前为了保命,独自 逃离了A 学校,抛弃了全校师生,包括那个曾经帮你计算并拆除道路的工程师。 你良心受到了巨大的谴责,因此决定做出一些补救,回答一些逃难的人提出的询 问。 已知该国一共有n 个城市,并且1 号城市是首都。(n-1)条双向的公路连接这些 城市,通过这些公路,任意两个城市之间存在且仅存在一条路径。每条公路有一 个长度。如果一个城市只与一条公路相连,则称它为边境城市。 该国政府有一个奇怪的规定:每个城市有一个封闭系数di,定义di为离这个城市最远的边境城市到这个城市的距离。市民们认为,一个城市的安全系数Si 和 它的封闭系数有很重要的联系。a,b,c 是该国的幸运数字,所以大家公认一个 城市的安全系数Si = (di + a) * b mod c。 市民们一共会提出m 次询问。每个询问包含三个信息,xi,yi和qi。xi是询问 者所在的城市编号。你要为这个询问者在xi 到yi 的必经之路上找出一个离xi 最近的避难城市,并且要求这个避难城市的安全系数大于等于qi。如果存在这样的城市(包含xi 和yi),则输出城市编号,否则输出一行包括一个数-1。
输入格式
第一行五个数:依次是n, m, a, b, c。 接下来n-1 行描述公路的信息。每行三个数,前两个数代表这条公路连接的两个 城市的编号,第三个数表示这条公路的长度。 再接下来m 行,每行描述一个询问,包含三个数xi, yi 和qi。
输出格式
对于每个询问,输出一行包含一个整数,存在符合要求的城市则输出城市编号, 不存在则输出-1。
输入样例
7 6 5 6 20
1 2 4
2 4 2
2 5 3
1 3 5
3 6 6
6 7 7
7 5 15
3 4 5
5 4 2
4 5 2
6 6 10
3 5 19
输出样例
6
3
2
4
6
-1
提示
【样例解释】
从城市1到城市7的安全系数依次是:18,2,8,14,0,18,0。
【数据范围】
对于100%数据, n<=100000, m<=300000, 0<xi, yi<=n; a,b,c,qi<=1,000,000, c!=0;
分析
既然每个边境城市的度数为1,那么以任意点作为根(除边境城市),边境城市一定是叶子节点。
进而推出直径的两端一定是边境城市,不然就不是最长。
先求出直径,就可以计算出每个城市的安全系数(为什么O(n)的遍历我要用Dijkstra啊啊啊啊啊啊
因为不带修改,所以考虑用倍增来维护
只需要维护最大值和最小值就好了
对于每次询问x,y,q,先找出x,y的lca,然后分别在x到lca,lca到y中找
因为到x最近,所以在x到lca中找时尽量找深度大的,在lca到y中尽量找深度小的
先考虑x到lca
对dep[x]-dep[lca]二进制拆分,如果x到x向上2^k的祖先无解,即这中间的安全系数的最大值不满足要求,则x向上跳2^k步
如果有解,则lca向下跳到x的2^k的祖先,但此时dep[x]-dep[lca]=2^k,而k这一位我们已经拆分过了,所以不妨让x再向上跳一格,使dep[x]-dep[lca]=2^k-1
就可以继续拆分了。
再考虑lca到y
此时因为要深度最小,所以要判断lca到某个节点是否有解,还要多写一个函数
同样对dep[y]-dep[lca]二进制拆分,如果y到y向上2^k的祖先无解,则y向上跳2^k步
如果有解,因为要深度最小,还要判断y向上2^k的祖先是否有解,如果有,则仍然是y向上跳2^k步,如果没有,则lca向下跳到y的2^k的祖先,y向上跳一步
注意特判x,y为同一个点的情况
代码
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int LOG=;
const int maxn=;
struct node{int id;long long w;};
bool operator <(node a,node b){return a.w<b.w;}
int n,m,a,b,c,p1,p2,ecnt,info[maxn],nx[maxn<<],v[maxn<<],w[maxn<<];
long long d[][maxn],dep[maxn];int val[maxn],vis[maxn],fa[maxn][],mx[maxn][];
void add(int u1,int v1,int w1){nx[++ecnt]=info[u1];info[u1]=ecnt;v[ecnt]=v1;w[ecnt]=w1;}
void dfs1(int x,int f){if(dep[x]>=dep[p1])p1=x;for(int e=info[x];e;e=nx[e])if(v[e]!=f)dep[v[e]]=dep[x]+w[e],dfs1(v[e],x);}
void DIJK(int x,int k)
{
memset(vis,,sizeof vis);priority_queue<node>q;q.push((node){x,});
while(!q.empty())
{
node nw=q.top();q.pop();
if(vis[nw.id])continue;vis[nw.id]=;d[k][nw.id]=nw.w;
for(int e=info[nw.id];e;e=nx[e])if(d[k][v[e]]<d[k][nw.id]+w[e]&&!vis[v[e]])
q.push((node){v[e],d[k][nw.id]+w[e]});
}
}
void dfs(int x,int f)
{
dep[x]=dep[fa[x][]=f]+;mx[x][]=max(val[x],val[f]);
for(int i=;i<=LOG;i++)fa[x][i]=fa[fa[x][i-]][i-],mx[x][i]=max(mx[x][i-],mx[fa[x][i-]][i-]);
for(int e=info[x];e;e=nx[e])if(v[e]!=f)dfs(v[e],x);
}
int Lca(int x,int y)
{
if(dep[y]>dep[x])swap(x,y);
for(int i=LOG;i>=;i--)if((dep[x]-dep[y])&(<<i))x=fa[x][i];if(x==y)return x=y;
for(int i=LOG;i>=;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];return fa[x][]=fa[y][];
}
int getans(int x,int y)
{
int ret=val[x];
for(int i=LOG;i>=;i--)if(dep[fa[x][i]]>=dep[y])ret=max(ret,mx[x][i]),x=fa[x][i];
return ret;
}
int find1(int x,int y,int q)
{
if(getans(x,y)<q)return ;
for(int i=;i>=;i--)if((dep[x]-dep[y])&(<<i))
{
if(mx[x][i]>=q)
{
y=fa[x][i];
if(val[x]>=q)return x;
x=fa[x][];
}
else x=fa[x][i];
}
return x;
}
int find2(int x,int y,int q)
{
if(getans(x,y)<q)return ;
for(int i=;i>=;i--)if((dep[x]-dep[y])&(<<i))
{
if(getans(fa[x][i],y)>=q)x=fa[x][i];
else
{
y=fa[x][i];
if(getans(fa[x][],y)>=q)x=fa[x][];
else return x;
}
}
return x;
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&a,&b,&c);
for(int i=,u1,v1,w1;i<n;i++)scanf("%d%d%d",&u1,&v1,&w1),add(u1,v1,w1),add(v1,u1,w1);
dfs1(,);p2=p1;p1=;memset(dep,,sizeof dep);dfs1(p2,);DIJK(p1,);DIJK(p2,);
for(int i=;i<=n;i++)val[i]=1ll*(max(d[][i],d[][i])+a)*b%c;dfs(,);
for(int i=,x,y,q,ret;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&q);
int lca=Lca(x,y);ret=;
if((ret=find1(x,lca,q))||(ret=find2(y,lca,q)))printf("%d\n",ret);
else puts("-1");
}
}
【CSP模拟赛】避难向导(倍增lca&树的直径)的更多相关文章
- 【csp模拟赛6】相遇--LCA
对于30%的数据:暴力枚举判断 对于60%的数据:还是暴力枚举,把两条路径都走一遍计一下数就行,出现一个点被访问两次即可判定重合 对于100%的数据:找出每条路径中距离根最近的点(lca),判断这个点 ...
- @省选模拟赛03/16 - T3@ 超级树
目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取 ...
- CSP模拟赛游记
时间:2019.10.5 考试时间:100分钟(连正式考试时间的一半还没有到)题目:由于某些原因不能公开. 由于第一次接触NOIinux系统所以连怎么建文件夹,调字体,如何编译都不知道,考试的前半小时 ...
- 7.18 NOI模拟赛 因懒无名 线段树分治 线段树维护直径
LINK:因懒无名 20分显然有\(n\cdot q\)的暴力. 还有20分 每次只询问一种颜色的直径不过带修改. 容易想到利用线段树维护直径就可以解决了. 当然也可以进行线段树分治 每种颜色存一下直 ...
- XTU1267:Highway(LCA+树的直径)
传送门 题意 有n个小镇,Bobo想要建造n-1条边,并且如果在u到v建边,那么花费是u到v的最短路长度(原图),问你最大的花费. 分析 比赛的时候没做出来,QAQ 我们首先要找到树的直径起点和终点, ...
- 【CSP模拟赛】天才绅士少女助手克里斯蒂娜(线段树&读入优化&输出优化)
题面描述 红莉栖想要弄清楚楼下天王寺大叔的显像管电视对“电话微波炉(暂定)”的影响.选取显像管的任意一个平面,一开始平面内有个n电子,初始速度分别为vi,定义飘升系数为 $$\sum_{1\leqsl ...
- 【CSP模拟赛】仔细的检查(树的重心&树hash)
题目描述 nodgd家里种了一棵树,有一天nodgd比较无聊,就把这棵树画在了一张纸上.另一天nodgd更无聊,就又画了一张. 这时nodgd发现,两次画的顺序是不一样的,这就导致了原本的某一个节点 ...
- 【CSP模拟赛】奇怪的队列(树状数组 &二分&贪心)
题目描述 nodgd的粉丝太多了,每天都会有很多人排队要签名. 今天有n个人排队,每个人的身高都是一个整数,且互不相同.很不巧,nodgd今天去忙别的事情去了,就只好让这些粉丝们明天再来.同时nod ...
- 【CSP模拟赛】God knows (李超线段树)
题面 CODE 稍微分析一下,发现把(i,pi)(i,p_i)(i,pi)看做二维数点,就是求极长上升子序列的权值最小值. 直接李超线段树 #include <bits/stdc++.h> ...
随机推荐
- jdk安装以及Java环境配置
jdk其实自己大一的时候就已经装过,java环境也配置过,但是随着后面学习的东西越来越多,要安装的软件也越来越多,一开始没有安装路径的概念,好多东西都放的很乱.接着这次自己复习java的机会,于是重新 ...
- BUAA_OO第三单元总结性博客作业——JML
一.JML 在第三单元的面向对象课程中我们第一次接触了JML语言以及基于JML规范的规格化设计.在之前一系列关于面向对象思想的学习认识中,我们知道了Java是一种面向对象的语言,面向对象思想的一个重要 ...
- Solr-rce历史漏洞复现
最近Solr又出了一个RCE漏洞,复现了一下 # coding: utf-8 import requestsimport argparsefrom urllib import parse if __n ...
- xcode 4 制作通用静态库
参考:http://blog.csdn.net/pjk1129/article/details/7255163 最近在做Apple的IOS开发,有开发静态库的需求,本身IOS的开发,只允许静态库或者F ...
- linux基础命令之1
1.创建文件夹:mkdir 文件夹名称 2.创建文件:touch 文件名称 3.编辑文件:vi 文件名称 4.保存文件::wq
- mysql基础知识整理(一)
一.数据库基本操作 登录: 开启数据库服务,在cmd中输入指令 mysql -u用户名 -p密码 3退出: 在cmd中输入exit/quit;启动服务: net start 服务名 停止服务:net ...
- sqlserver存储过程里传字段、传字符串,并返回DataTable、字符串,存储过程调用存储过程。
经常需要查一些信息, 想写视图来返回数据以提高效率,但是用试视图不能传参,只好想到改存储过程.记录一下语法,方便以后做项目时候想不起来了用. 1:传字段返回datatable 2: 传字段回一串字符 ...
- 【JUC】7.CountDownLatch
Latch:门闩.一种线程通信的方式:当程序不涉及同步,仅仅需要线程通信的时候,使用synchronize或者lock的线程通信等待唤醒机制,就显得太重了: 这时候,可以考虑使用信号量类:CountD ...
- LFS7.10——构造临时Linux系统
参考:LFS编译——准备Host系统 前言 在准备好Host环境后,接下来构造一个临时Linux系统.该系统包含****构建所需要的工具.构造临时Linux系统分两步: 构建一个宿主系统无关的新工具链 ...
- 使用ansible部署CDH 5.15.1大数据集群
使用ansible离线部署CDH 5.15.1大数据集群 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在此之前,我之前分享过使用shell自定义脚本部署大数据集群,不管是部署CD ...