[CSP-S模拟测试]:Dash Speed(线段树+并查集+LCA)
题目描述
比特山是比特镇的飙车圣地。在比特山上一共有$n$个广场,编号依次为$1$到$n$,这些广场之间通过$n−1$条双向车道直接或间接地连接在一起,形成了一棵树的结构。
因为每条车道的修建时间以及建筑材料都不尽相同,所以可以用两个数字$l_i,r_i$量化地表示一条车道的承受区间,只有当汽车以不小于$l_i$且不大于$r_i$的速度经过这条车道时,才不会对路面造成伤害。
$Byteasar$最近新买了一辆跑车,他想在比特山飙一次车。$Byteasar$计划选择两个不同的点$S,T$,然后在它们树上的最短路径上行驶,且不对上面任意一条车道造成伤害。
$Byteasar$不喜欢改变速度,所以他会告诉你他的车速。为了挑选出最合适的车速,$Byteasar$一共会向你询问$m$次。请帮助他找到一条合法的道路,使得路径上经过的车道数尽可能多。
输入格式
第一行包含两个正整数$n,m$,表示广场的总数和询问的总数。
接下来$n−1$行,每行四个正整数$u_i,v_i,l_i,r_i$,表示一条连接$u_i$和$v_i$的双向车道,且承受区间为$[l_i,r_i]$。
接下来$m$行,每行一个正整数$q_i$,分别表示每个询问的车速。
输出格式
输出$m$行,每行一个整数,其中第$i$行输出车速为$q_i$时的最长路径的长度,如果找不到合法的路径则输出$0$。
样例
我们将速度$l,r$看成区间,那么我们就是要找速度是$q_i$时所能经过多少连续区间。
现将问题离线。
那么可以用线段树维护边,对于线段树上区间$l,r$,我们将边的这条边压进去。
然后我们在线段树上往上合并每一条边,用并查集维护是否已经连到了一起,合并时一共分为$6$种情况;注意并查集不能路径压缩,要按秩合并,因为我们在合并的同时还要维护信息。
对于合并时求距离,还是用$LCA$,但是倍增$LCA$常数较大,建议用树链剖分。
时间复杂度:$\Theta(n\log^2n)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct rec{int nxt,to;}e[150000];
struct node{int x,y,v;pair<int,int> p;}sta[70001];
int head[70001],cnt;
int n,m,t;
int f[70001],dep[70001];
pair<int,int> st[70001];
int fa[70001],depth[70001],top[70001],size[70001],son[70001];
vector<pair<int,int> > pos[500000];
int ans[70001];
void add(int x,int y)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
int find(int x){return x==f[x]?x:find(f[x]);}
void dfs1(int x)
{
size[x]=1;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa[x])
{
fa[e[i].to]=x;
depth[e[i].to]=depth[x]+1;
dfs1(e[i].to);
size[x]+=size[e[i].to];
if(size[e[i].to]>size[son[x]])son[x]=e[i].to;
}
}
void dfs2(int x,int tp)
{
top[x]=tp;
if(!son[x])return;
dfs2(son[x],tp);
for(int i=head[x];i;i=e[i].nxt)
if(!top[e[i].to])dfs2(e[i].to,e[i].to);
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(depth[top[x]]<depth[top[y]])swap(x,y);
x=fa[top[x]];
}
return depth[x]<depth[y]?x:y;
}
int dis(int x,int y){return depth[x]+depth[y]-(depth[LCA(x,y)]<<1);}
void build(int x,int l,int r,int L,int R,int u,int v)
{
if(r<L||R<l)return;
if(L<=l&&r<=R){pos[x].push_back(make_pair(u,v));return;}
int mid=(l+r)>>1;
build(L(x),l,mid,L,R,u,v);
build(R(x),mid+1,r,L,R,u,v);
}
void merge(int x,int y,int &flag)
{
x=find(x);
y=find(y);
int res=0,d;
pair<int,int> mzz;
if(res<(d=dis(st[x].first,st[x].second)))res=d,mzz=make_pair(st[x].first,st[x].second);
if(res<(d=dis(st[x].first,st[y].first)))res=d,mzz=make_pair(st[x].first,st[y].first);
if(res<(d=dis(st[x].first,st[y].second)))res=d,mzz=make_pair(st[x].first,st[y].second);
if(res<(d=dis(st[x].second,st[y].first)))res=d,mzz=make_pair(st[x].second,st[y].first);
if(res<(d=dis(st[x].second,st[y].second)))res=d,mzz=make_pair(st[x].second,st[y].second);
if(res<(d=dis(st[y].first,st[y].second)))res=d,mzz=make_pair(st[y].first,st[y].second);
flag=max(flag,res);
if(dep[x]<dep[y])swap(x,y);
sta[++t]=(node){x,y,0,st[x]};
if(dep[x]==dep[y])
{
dep[x]++;
sta[t].v=1;
}
f[y]=x;
st[x]=mzz;
}
void del(int x)
{
while(x<t)
{
dep[sta[t].x]-=sta[t].v;
f[sta[t].y]=sta[t].y;
st[sta[t].x]=sta[t].p;
t--;
}
}
void solve(int x,int l,int r,int res)
{
int now=t;
for(int i=0;i<pos[x].size();i++)
merge(pos[x][i].first,pos[x][i].second,res);
if(l==r){ans[l]=res;del(now);return;}
int mid=(l+r)>>1;
solve(L(x),l,mid,res);
solve(R(x),mid+1,r,res);
del(now);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
int u,v,l,r;
scanf("%d%d%d%d",&u,&v,&l,&r);
add(u,v);add(v,u);
build(1,1,n,l,r,u,v);
}
dfs1(1);
dfs2(1,1);
for(int i=1;i<=n;i++)
{
f[i]=i;
st[i]=make_pair(i,i);
}
solve(1,1,n,0);
while(m--)
{
int x;scanf("%d",&x);
printf("%d\n",ans[x]);
}
return 0;
}
rp++
[CSP-S模拟测试]:Dash Speed(线段树+并查集+LCA)的更多相关文章
- [WC2005]双面棋盘(线段树+并查集)
线段树+并查集维护连通性. 好像 \(700ms\) 的时限把我的常数超级大的做法卡掉了, 必须要开 \(O_2\) 才行. 对于线段树的每一个结点都开左边的并查集,右边的并查集,然后合并. \(Co ...
- 2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集)
2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集) https://www.luogu.com.cn/problem/CF811E Ste ...
- 联赛模拟测试8 Dash Speed 线段树分治
题目描述 分析 对于测试点\(1\).\(2\),直接搜索即可 对于测试点\(3 \sim 6\),树退化成一条链,我们可以将其看成序列上的染色问题,用线段树维护颜色相同的最长序列 对于测试点\(7\ ...
- [CSP-S模拟测试]:Weed(线段树)
题目描述 $duyege$的电脑上面已经长草了,经过辨认上面有金坷垃的痕迹.为了查出真相,$duyege$准备修好电脑之后再进行一次金坷垃的模拟实验.电脑上面有若干层金坷垃,每次只能在上面撒上一层高度 ...
- [CSP-S模拟测试]:光线追踪(线段树)
题目背景 初中时的乔猫试着组建了$NEWorld$开发组,可是不久之后却因为合作上的问题(和乔猫工程水平差,代码混乱的问题),开发组成员之间常常产生矛盾,关系越来越不如以前......一年下来,受到长 ...
- [CSP-S模拟测试]:椎(线段树维护区间最值和单调栈)
题目描述 虽不能至,心向往之. $Treap=Tree+Heap$ 椎$=$树$+$堆 小$\pi$学习了计算机科学中的数据结构$Treap$. 小$\pi$知道$Treap$指的是一种树. 小$\p ...
- [CSP-S模拟测试]:bird(线段树优化DP)
题目传送门(内部题89) 输入格式 第一行两个数$n$和$k$,分别表示小鸟的只数和$R$装弹时间.接下来$n$行,每行两个数$l,r$表示$n$只小鸟初始时的头和尾的$x$坐标. 输出格式 输出一个 ...
- [CSP-S模拟测试]:string(线段树)
题目描述 给定一个由小写字母组成的字符串$s$. 有$m$次操作,每次操作给定$3$个参数$l,r,x$. 如果$x=1$,将$s[l]~s[r]$升序排序: 如果$x=0$,将$s[l]~s[r]$ ...
- [CSP-S模拟测试]:Permutation(线段树+拓扑排序+贪心)
题目描述 你有一个长度为$n$的排列$P$与一个正整数$K$你可以进行如下操作若干次使得排列的字典序尽量小对于两个满足$|i−j|\geqslant K$且$|P_i−P_j|=1$的下标$i$与$j ...
随机推荐
- json 格式
Json格式规则:(Douglas Crockford提出的) 1) 并列的数据之间用逗号(“,”)分隔. 2) 映射用冒号(“:”)表示. 3) 并列数据的集合(数组)用方括号("[]&q ...
- Navicat12安装与激活
安装Navicat 1.下载软件和激活工具 链接:https://pan.baidu.com/s/1pFo2BkZYPpPFldG-fhbzIA&shfl=sharepset 提取码:xs97 ...
- Parameter setting for Jemeter Post method
1. create CSV file note: the first line is parameter name 2. Add Controller Edit >Add >Logic C ...
- mysql : 使用不等于过滤null的问题
在写sql时遇到查询结果不对的情况,经查阅,发现是因为查询条件过滤null的问题:从网上找到如下资料: 在写SQL 条件语句是经常用到 不等于‘!=’的筛选条件,此时要注意此条件会将字段为null的数 ...
- uWSGI、uwsgi、WSGI、之间的关系,为什么要用nginx加uWSGI部署。
WSGI 协议 WSGI:是一种协议规范,起到规范参数的作用,就像告诉公路一样,规定超车靠右行,速度不低于90km/h,等.但这一切都是对双方进行沟通,比如,重庆到武汉这条高速路,这儿重庆和武汉就各为 ...
- SQL中的like '%%‘查询
一,我们正常使用like时,这是有两个条件的模糊查询 select *From Test where UserName like '%m%' and UserName like '%a%' 二,但这时 ...
- Sublime Text插件安装方法和常用插件
插件安装方法: 1.打开Sublime Text,按下Ctrl+Shift+P调出命令面板 ; 2.输入install 调出 Install Package Control选项并回车; 3.再次按下C ...
- idea 创建java web项目ssm-gradle
环境准备:jdk1.8+tomcat8+idea+gradle 1.创建项目SSM 使用gradle创建项目,按照提示如下 image.png 输入项目名称,组名 image.png im ...
- MySQL 简介
MySQL 简介 点击查看MySQL官方网站 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,后来被Sun公司收购,Sun公司后来又被Oracle公司收购,目前属于Oracle旗 ...
- Java架构师需要掌握的技术栈