zoukankan      html  css  js  c++  java
  • [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(nlog^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
    ",ans[x]);
    	}
    	return 0;
    }

    rp++

  • 相关阅读:
    Leetcode Array 4 Median of Two Sorted Arrays
    vscode Python Pylint(代码检测插件)
    Leetcode Array 1 twoSum
    mysql 配置 安装和 root password 更改
    vscode 编译调试c/c++的环境配置
    chm文件打不开的解决办法
    A + B Problem II
    欢天喜地七仙女——代码规范与计划
    欢天喜地七仙女——项目系统设计与数据库设计
    欢天喜地七仙女——团队Gitee实战训练
  • 原文地址:https://www.cnblogs.com/wzc521/p/11623020.html
Copyright © 2011-2022 走看看