这题我们要求的是啥呢?仔细读题可以发现,工人传送带的关系可以看成一个 \(n\) 个点和 \(m\) 条边的无向图,然后对于每组询问 \((a,L)\),其实就是问:

\(1\) 到 \(a\) 有没有一条长度为 \(L\) 的路径。


我们换个角度思考一下,如果已知 \(1\) 到 \(a\) 有一条长度为 \(S\) 的路径,我们在这条路径上任选一条边重复走一次,那么就会出现一条 \(1\) 到 \(a\) 长度为 \(S+2\)的路径 ,同理,也会有 \(1\) 到 \(a\) 长度为 \(S+4\),也会有 \(1\) 到 \(a\) 长度为 \(S+6\) 的路径\(.......\)

那么我们可以知道:若 \(1\) 到 \(a\) 有一条长度为 \(S\) 的路径,其中 \(S \leq L\) 且 \(S\equiv L\pmod{2}\),那么 \(1\) 到 \(a\) 有一条长度为 \(L\) 的路径。

为了统计更多的信息,我们要使得对于每个 \(a\) 求出的 \(S\) 最小,以及保证奇偶性一致,那么很明显就是分 奇\(/\)偶 求最短路了。

设 \(d[a][1/0]\) 表示 \(1\) 到 \(a\) 路径长度为 奇\(/\)偶 的最短路长度,特别的,若 \(1\) 到 \(a\) 没有路径长度为 奇\(/\)偶 的路径,则 \(d[a][1/0]\) 为正无穷。初始时 \(d[1][0]=0\) ,其他均为正无穷。

考虑到 "奇路径\(+1\)为偶路径" 与 "偶路径\(+1\)为奇路径" ,那么对于一条边 \((u,v)\) ,我们都可以尝试用 \(d[u][0]+1\) 去更新 \(d[v][1]\),尝试用 \(d[u][1]+1\) 更新 \(d[v][0]\)。

这里拿 \(SPFA\) 做例子(别问为什么是这个死了的算法,问就是边权为 \(1\) 卡不掉,\(dijkstra\)同),具体的,在 \(SPFA\) 的过程中,在队列里多维护一个信息,表示松弛该节点时是奇最短路还是偶最短路(记为 \(type \in\{ 0,1\}\) ),对于每次松弛的节点 \(u\) ,扫描 \(u\) 的每一条出边 \((u,v)\) ,尝试用 \(d[u][type]+1\) 更新 \(d[v][type \ xor \ 1]\),若更新成功且二元组 \((v,type \ xor \ 1)\) 不在队中,再把\((v,type \ xor \ 1)\)插入队尾,直至队列为空,这样就处理好了 \(d\) 数组。

对于每组询问\((a,L)\), \(Θ(1)\) 比较 \(d[a][L\&1]\) 与 \(L\) 的大小关系即可。

需要注意的是,可能会有 \(1\) 号节点与所有点都没有连边的毒瘤数据,此时根据题意,当 \(a=1\) 时,无论 \(L\) 的取值,答案都是 \(NO\) ,但初始化时 \(d[1][0]=0\) ,如果 \(L\equiv 0\pmod{2}\),则会输出 \(YES\)。此处需要特判一下,判断 \(1\) 号节点与所有点都没有连边的情况只需判断 \(1\) 号节点的表头是否为 \(0\) 即可(邻接表存边)


Code 部分

\(SPFA\)版本:

#include<cstdio>
#include<cstring>
#include<queue> #define RI register int using namespace std; inline int read()
{
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
return x*f;
} const int N=100100,M=200100; int n,m,Q; int tot,head[N],ver[M],edge[M],Next[M]; void add(int u,int v,int w)//邻接表
{
ver[++tot]=v; edge[tot]=w; Next[tot]=head[u]; head[u]=tot;
} struct data{//队中节点数据
int type;// 奇/偶 最短路
int name;//编号
}; int d[N][2];
int vis[N][2]; void SPFA()
{
memset(d,0x3f,sizeof(d));
d[1][0]=0;
queue<data>q;
q.push((data){0,1});
while(q.size())
{
data u=q.front();q.pop();vis[u.name][u.type]=0;//取出队头
for(RI i=head[u.name];i;i=Next[i])
{
int v=ver[i],w=edge[i];
if(d[u.name][u.type]+w<d[v][u.type^1])//能够更新
{
d[v][u.type^1]=d[u.name][u.type]+w;//更新
if(!vis[v][u.type^1])
{
vis[v][u.type^1]=1;//标记
q.push((data){u.type^1,v});//入队
}
}
}
}
} int main()
{
n=read(),m=read(),Q=read();
for(RI i=1;i<=m;i++)
{
int u=read(),v=read();
add(u,v,1),add(v,u,1);//加边
} SPFA(); while(Q--)
{
int a=read(),L=read();
if(d[a][L&1]<=L&&(a!=1||head[a])/*特判*/)
puts("Yes");
else
puts("No");
} return 0;
}

\(dijkstra\)版本:

#include<cstdio>
#include<cstring>
#include<algorithm> #define RI register int using namespace std; inline int read()
{
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
return x*f;
} const int N=100100,M=200100; int n,m,Q; int tot,head[N],ver[M],edge[M],Next[M]; void add(int u,int v,int w)//邻接表
{
ver[++tot]=v; edge[tot]=w; Next[tot]=head[u]; head[u]=tot;
} int len;
struct data{//堆中节点数据
int tpye;// 奇/偶 最短路
int dis;//长度
int name;//编号
}heap[N]; void put(data x)//入堆操作
{
heap[++len]=x;
int now=len;
while(now)
{
int nxt=now/2;
if(heap[nxt].dis<=heap[now].dis)break;
swap(heap[nxt],heap[now]);
now=nxt;
}
} void change()//堆顶出堆
{
heap[1]=heap[len--];
int now=1;
while(now*2<=len)
{
int nxt=now*2;
if(nxt+1<=len&&heap[nxt].dis>heap[nxt+1].dis)nxt++;
if(heap[now].dis<=heap[nxt].dis)break;
swap(heap[now],heap[nxt]);
now=nxt;
}
} int d[N][2];
int vis[N][2]; void dijkstra()
{
memset(d,0x3f,sizeof(d));
d[1][0]=0;
put((data){0,0,1});
while(len)
{
data u=heap[1];change();//取出堆顶
if(vis[u.name][u.tpye])continue;
vis[u.name][u.tpye]=1;//标记
for(RI i=head[u.name];i;i=Next[i])
{
int v=ver[i],w=edge[i];
if(d[u.name][u.tpye]+w<d[v][u.tpye^1])//能够更新
{
d[v][u.tpye^1]=d[u.name][u.tpye]+w;//更新
put((data){u.tpye^1,d[v][u.tpye^1],v});//入堆
}
}
}
} int main()
{
n=read(),m=read(),Q=read();
for(RI i=1;i<=m;i++)
{
int u=read(),v=read();
add(u,v,1),add(v,u,1);//加边
} dijkstra(); while(Q--)
{
int a=read(),L=read();
if(d[a][L&1]<=L&&(a!=1||head[a])/*特判*/)
puts("Yes");
else
puts("No");
} return 0;
}

Thanks for watching

题解 CSP2019-J2T4【加工零件】的更多相关文章

  1. 题解 P5663 【加工零件【民间数据】】

    博客园体验更佳 讲讲我的做法 确定做法 首先,看到这道题,我直接想到的是递归,于是复杂度就上天了,考虑最短路. 如何用最短路 首先,看一张图 我们该如何解决问题? 问题:\(3\)做\(5\)阶段的零 ...

  2. P5663 加工零件

    P5663 加工零件 题解 暴力搜索 搜索显然会TLE #include<iostream> #include<cstdio> #include<cstdlib> ...

  3. P5663 加工零件 题解

    原题链接 简要题意: 给定一个图,每次询问从 \(x\) 节点开始,\(y\) 步能不能达到 \(1\) 号节点. 算法一 这也是我本人考场算法.就是 深搜 . 因为你会发现,如果 \(x\) 用 \ ...

  4. 洛谷 P5663 加工零件

    题目传送门 解题思路: 最暴力的做法: bfs模拟,每次将一个阶段的所有点拿出来,将其所有直连的点都放进队列,知道本阶段结束,最后看1号点会不会在最后一个阶段被放入队列.(洛谷数据40分) 优化了一下 ...

  5. 2019CSP-J T4 加工零件

    题目描述 凯凯的工厂正在有条不紊地生产一种神奇的零件,神奇的零件的生产过程自然也很神奇.工厂里有 n 位工人,工人们从 1 ∼n 编号.某些工人之间存在双向的零件传送带.保证每两名工人之间最多只存在一 ...

  6. 洛谷 P5663 加工零件 & [NOIP2019普及组] (奇偶最短路)

    传送门 解题思路 很容易想到用最短路来解决这一道问题(题解法),因为两个点之间可以互相无限走,所以如果到某个点的最短路是x,那么x+2,x+4也一定能够达到. 但是如何保证这是正确的呢?比如说到某个点 ...

  7. 题解 P1248 【加工生产调度】

    题目 某工厂收到了 n 个产品的订单,这 n 个产品分别在 A.B 两个车间加工,并且必须先在 A 车间加工后才可以到 B 车间加工. 某个产品 i 在 A.B 两车间加工的时间分别为 Ai,Bi 怎 ...

  8. [题解]CSP2019 Solution - Part B

    \(\text{orz}\) 一波现场 \(\text{A}\) 掉 \(\text{D1T3}\) 的神仙 D2T3 centroid Solution 考虑每个点 \(u\) 作为重心的贡献 假设 ...

  9. [题解]CSP2019 Solution - Part A

    至于为什么是 \(\text{Part A}\) 而不是 \(\text{Day 1}\) 那是因为 Day1 T3 还没改 (那这六题的 \(\text{solution}\) 就按难度顺序写吧) ...

随机推荐

  1. 比特币学习笔记(一)---在windows下编译搭建比特币环境

    最近打算研究下比特币源码,却发现这套源码正常情况下得在linux下编译运行,而我的机器是windows的. 怎么办呢? 起初打算用mingw和cygwin搞搞看,试了许久后发现行不通,必须转到linu ...

  2. 条款03:尽可能使用const

    目录 1. 总结 2. const对象 3. const函数返回值和函数参数 4. const成员函数 const成员函数的重要性 bitwise constness logical constnes ...

  3. TieredMergePolicy

    setFloorSegmentMB多少MB一个层级,在此区间的segment分为一个floor. setMaxMergeAtOnce一次merge多少个segment. setSegmentsPerT ...

  4. 探究Dubbo的拓展机制: 下

    承接上篇, 本篇博文的主题就是认认真真捋一捋, 看一下 Dubbo是如何实现他的IOC / AOP / 以及Dubbo SPI这个拓展点的 总览: 本篇的话总体上分成两部分进行展开 第一点就是 Dub ...

  5. MongoDB Community 的安装和卸载

    MongoDB在他们的仓库中提供官方支持的包,该仓库包括以下软件包 mongodb-org:自动安装下面的四个组件安装包 a.mongodb-org-server:mongod的守护进程和相关的配置以 ...

  6. C#实现的对文件的重命名

    如下C#实现对文件的重命名的方法需要传入三个string类型的参数,分别是源文件的文件目录.目的文件目录和重命名的文件名称,实现代码如下: public ExecutionResult FileRen ...

  7. Java 用链表实现栈和队列

    栈 是一种基于后进先出(LIFO)策略的集合类型.当邮件在桌上放成一叠时,就能用栈来表示.新邮件会放在最上面,当你要看邮件时,会一封一封从上到下阅读.栈的顶部称为栈顶,所有操作都在栈顶完成. 前面提到 ...

  8. CDH安装详细测试正确

    1. CDH简介 简单来说,Cloudera Manager是一个拥有集群自动化安装.中心化管理.集群监控.报警功能的一个工具(软件),使得安装集群从几天的时间缩短在几个小时内,运维人员从数十人降低到 ...

  9. JMeter——聚合报告

    AggregateReport 是 JMeter 常用的一个 Listener,中文被翻译为“聚合报告”. ​ 对于每个请求,它统计响应信息并提供请求数,平均值,最大,最小值,错误率,大约吞吐量(以请 ...

  10. oa办公系统是什么?对企业有什么作用?

    OA办公系统是指利用计算机网络帮助企业实现办公自动化,用系统软件代替传统的手工工作帮助企业处理内部事务,例如文档共享.部门协作.报销.业务流程等等,最终目的帮助企业提高工作效率,实现利益最大化. 随着 ...