Test 2022.10.08

今天是鸡杂专场

T1 跳楼

题意

就是给出每栋楼的高度,然后有两个约束条件,分别对应前一项、前两项的递推关系,然后从第一栋楼开始,求最后能否到达第n栋楼

分析

简简单单一个和前两项有关的递推,注意如果当一栋楼的前两栋楼都不能到达,那么后面的所有楼一定都是不能到达的,所以这个时候就直接可以break掉输出了,有一个小细节就是memset重置vis数组的时候可以改为在输入的时候用循环展开的原理去做,这样不会T掉后面三个点

Code

点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
template <typename T>inline void re(T &x)
{
x=0;
int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-f;
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^48);
x*=f;
return;
}
template <typename T>void wr(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) wr(x/10);
putchar(x%10^'0');
return;
}
const int maxn=1e5+100;
int t,n,d1,d2;int h[maxn];
int abs1(int x){return x>0?x:-x;}
bool check1(int h1,int h2){return abs1(h1-h2)<=d1;}
bool check2(int h1,int h2,int h3){return h1>h2&&h2<h3&&abs1(h1-h3)<=d2;}
int vis[maxn];
int main()
{
re(t);
while(t--)
{
re(n),re(d1),re(d2);
for(register int i=1;i<=n;++i)re(h[i]),vis[i]=0;
if(n==1){puts("Yes");continue;}
vis[1]=1;if(check1(h[1],h[2]))vis[2]=1;
for(register int i=3;i<=n;++i)
{
if(vis[i-1]==0&&vis[i-2]==0)break;
if(vis[i-1]&&check1(h[i-1],h[i])){vis[i]=1;continue;}
if(vis[i-2]&&check2(h[i-2],h[i-1],h[i]))vis[i]=1;
}
if(vis[n])puts("Yes");
else puts("No");
}
return 0;
}
/*
5
1 5 19
10
14 18 5
13 3 8 16 12 4 17 18 20 13 5 14 13 8
8 3 1
12 11 13 7 9 9 16 17
3 17 5
20 20 6
4 1 12
11 9 13 9
*/

T2 Control

题意

给出一个有向图,定义:如果一个点能掌控一个点,那么他的所有儿子都能掌控这个点(有点像递归的定义),换句话说,这个点所引出的所有路径都必须能到达要被掌控的点

分析

从上面的题意转化,我们很简单的就能想到一个暴力思路,O(n2)枚举所有点,判断是否一个点是否能被另一个点掌控就行了,实现这个过程只需要建和样例解释相反的边,然后一个很短小的dfs就行了,下面就只贴dfs的代码了

点击查看代码
bool dfs(int x,int t)//判断x是否能掌控t
{
if(x==t)return 1;
for(register int i=head[x];i;i=E[i].nex)if(!dfs(E[i].v,t))return 0;
if(!head[x])return 0;//这个点没有儿子了
else return 1;
}

正解

我们思考能否简化这张图,建立一个树形的关系结构可以直接形容控制与否的关系(一个点的直接父亲就是他能够控制的点),来通过树上差分或者是lca等时间代价更小的算法呢?

建图

首先对于我们要加入的点,给出他的儿子节点,在之前构建的图的基础上面,满足题意的点只有给出的所有儿子的lca以及lca的所有父亲,那我们就直接在当前点和lca之间连边,表示当前点可以掌控lca及其以上的节点,一边加入点,一边更新倍增的F数组和点的深度,注意还要引入一个超级父亲x

统计答案

所以有了这个图,我们很清楚的知道对于任意两个询问中给出的点,答案就是他们到根节点0的路径并集中的节点数量,那么问题就是我们该怎么样去求这个并集的元素数,先看下面这张图image
我们假定A节点是0号节点,我们现在要求C到H的答案,首先C的深度是3,H的深度是4,用C+H会重复统计的答案就是:他们的lca的深度和多统计的一个根节点0,所以最后的ans就是3+421=4
现在拓展到三个点的情况:C,H,I,E,先上代码

点击查看代码
scanf("%d",&k);
for(register int i=1;i<=k;i++)scanf("%d",&s[++top]);
sort(s+1,s+top+1,cmp);
int ans=0;
while(top)ans+=dep[s[top]]-dep[LCA(s[top],s[top-1])],top--;

显而易见的是,最后一行代码就是最核心的地方,当然,从左到右按照dfn序来统计答案也比较重要
按照从左到右的顺序:

首先考虑C,H:我们只统计lca以下的答案,也就是dep[C]dep[LCA(C,H)=B]=1那么还有B以上没有统计到的部分呢?不着急,往下看

再考虑H,I:我们依然和上面一样只考虑lca以下的答案,那么就是dep[H]dep[LCA(H,I)=D]=1

同理考虑I,E:这时候统计到的答案就是dep[I]dep[LCA(I,E)=B]=2

最后考虑E,0(A):按照我们刚刚的算法,最后统计到的就是dep[E]dep[LCA(E,A)=A]=2

用一张图来描述我们统计答案的过程就是这样的:
image

Code

点击查看代码
posted @   Hanggoash  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
动态线条
动态线条end
点击右上角即可分享
微信分享提示