[LOJ3057] [HNOI2019] 校园旅行
题目链接
LOJ:https://loj.ac/problem/3057
洛谷:https://www.luogu.org/problemnew/show/P5292
Solution
先膜一发\(myy\),这里是官方题解。
对于\(30\)分,可以得到一个很显然的做法:设\(f[i][j]\)表示\(i\to j\)的答案,然后枚举\(i,j\)的出边转移,这样做是\(O(m^2)\)的。
对于\(100\)分,注意到点的规模没变,我们有一个缩边的想法。
我们把边分成三类,同色的两种和异色的一种,对每类分别建图,然后我们对每个联通块进行考虑:
- 如果当前联通块是二分图,那么可以说明从\(i\)点到\(j\)点所经过的边数必然只能是奇数或偶数,那么我们任意处理出一棵生成树,容易发现这棵生成树和原图等价(如果这边多走了就在另一边来回走以抵消)。
- 如果当前联通块不是二分图,那么边数可以是奇数或偶数,那么我们只需要在生成树任意加一个自环就好了,这样的话就可以满足边数任意奇偶,注意异色边建出来的图不可能有这种情况。
缩完之后可以发现边数是\(O(n)\)级别的,那么我们套用上边的暴力,复杂度达到了\(O(n^2)\),足已通过此题。
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
#define lf double
#define ll long long
const int maxn = 2e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
char s[maxn];
int n,m,Q,vis[maxn],sta[maxn],top,f[5050][5050],flag;
struct Graph {
int head[maxn],tot,fa[maxn];
struct edge{int to,nxt;}e[maxn*20];
void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
void ins(int u,int v) {add(u,v),add(v,u);}
void dfs(int x,int c) {
vis[x]=c,sta[++top]=x;
for(int i=head[x];i;i=e[i].nxt)
if(!vis[e[i].to]) dfs(e[i].to,3-c),fa[e[i].to]=x;
else flag|=(vis[e[i].to]!=3-c);
}
void solve() {
queue<pair<int,int > > q;
for(int i=1;i<=n;i++) f[i][i]=1,q.push(make_pair(i,i));
for(int x=1;x<=n;x++)
for(int i=head[x];i;i=e[i].nxt)
if(s[x]==s[e[i].to]) f[x][e[i].to]=1,q.push(make_pair(x,e[i].to));
while(!q.empty()) {
int x=q.front().first,y=q.front().second;q.pop();
for(int i=head[x];i;i=e[i].nxt)
for(int u,v,j=head[y];j;j=e[j].nxt)
if(s[u=e[i].to]==s[v=e[j].to])
if(!f[u][v]) f[u][v]=1,q.push(make_pair(u,v));
}
}
}g[3],t;
int main() {
read(n),read(m),read(Q);scanf("%s",s+1);
for(int i=1,x,y;i<=m;i++) {
read(x),read(y);
if(s[x]!=s[y]) g[0].ins(x,y);
else if(s[x]=='1') g[1].ins(x,y);
else g[2].ins(x,y);
}
for(int i=0;i<=2;i++) {
memset(vis,0,sizeof vis);
for(int j=1;j<=n;j++)
if(!vis[j]) {
top=flag=0,g[i].dfs(j,1);
while(top) {
int x=sta[top];
if(g[i].fa[x]) t.ins(g[i].fa[x],x);top--;
}if(flag) t.ins(j,j);
}
}
t.solve();
for(int i=1,x,y;i<=Q;i++) read(x),read(y),puts(f[x][y]?"YES":"NO");
return 0;
}
[LOJ3057] [HNOI2019] 校园旅行的更多相关文章
- 【BZOJ5492】[HNOI2019]校园旅行(bfs)
[HNOI2019]校园旅行(bfs) 题面 洛谷 题解 首先考虑暴力做法怎么做. 把所有可行的二元组全部丢进队列里,每次两个点分别向两侧拓展一个同色点,然后更新可行的情况. 这样子的复杂度是\(O( ...
- [HNOI2019]校园旅行(构造+生成树+动规)
题目 [HNOI2019]校园旅行 做法 最朴素的做法就是点对扩展\(O(m^2)\) 发现\(n\)比较小,我们是否能从\(n\)下手减少边数呢?是肯定的 单独看一个颜色的联通块,如果是二分图,我们 ...
- Luogu P5292 [HNOI2019]校园旅行
非常妙的一道思博题啊,不愧是myy出的题 首先我们考虑一个暴力DP,直接开一个数组\(f_{i,j}\)表示\(i\to j\)的路径能否构成回文串 考虑直接拿一个队列来转移,队列里存的都是\(f_{ ...
- [HNOI2019]校园旅行
题意 https://www.luogu.org/problemnew/show/P5292 思考 最朴素的想法,从可行的二元组(u,v)向外拓展,及u的出边所指的颜色与v的出边所指的颜色若相同,继续 ...
- 洛谷P5292 [HNOI2019]校园旅行(二分图+最短路)
题面 传送门 题解 如果暴力的话,我们可以把所有的二元组全都扔进一个队列里,然后每次往两边更新同色点,这样的话复杂度是\(O(m^2)\) 怎么优化呢? 对于一个同色联通块,如果它是一个二分图,我们只 ...
- 【洛谷5292】[HNOI2019] 校园旅行(思维DP)
点此看题面 大致题意: 给你一张无向图,每个点权值为\(0\)或\(1\),多组询问两点之间是否存在一条回文路径. 暴力\(DP\) 首先,看到\(n\)如此之小(\(n\le5000\)),便容易想 ...
- bzoj5492:[Hnoi2019]校园旅行
传送门 %%%myy 考虑30分做法:暴力bfs,\(f[i][j]\)表示\(i\)到\(j\)可以形成回文串 然而为什么我场上只想到了70分做法,完全没想到30分怎么写.. 100分: 考虑缩边, ...
- [HNOI2019]校园旅行(建图优化+bfs)
30分的O(m^2)做法应该比较容易想到:令f[i][j]表示i->j是否有解,然后把每个路径点数不超过2的有解状态(u,v)加入队列,然后弹出队列时,两点分别向两边搜索边,发现颜色一样时,再修 ...
- Loj #3057. 「HNOI2019」校园旅行
Loj #3057. 「HNOI2019」校园旅行 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你 ...
随机推荐
- SpringBoot-03:SpringBoot+Idea热部署
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 所谓热部署,就是在项目启动中,修改class类中做的修改操作,无需重新启动项目,就可以变更,在网页展示中有 ...
- oracle_列转行
wmsys.wm_concat 将表中数据 如 ID USERNAME TYPE 1 刘 下 1 刘 ...
- 2019年猪年海报PSD模板-第七部分
14套精美猪年海报,免费猪年海报,下载地址:百度网盘,https://pan.baidu.com/s/1pE3X9AYirog1W8FSxbMiAQ
- http知识点 前端
前端必须明白的http知识点 对于http的报文格式就不多细说了,做为前端开发,我们需要知道前后端联调时的请求和响应之间请求头和返回头之间的关系和每个字段中的涵意,静态文件资源在加载时我们所观察到可性 ...
- Jmeter做压力测试的心得
什么是性能压测? 也是最近刚刚接触到,就是被测试的系统,在一定的访问压力下,看程序运行是否稳定/服务器运行是否稳定,通常情况,是模拟多个请求同时 请求服务器,也就是在某个时间内,比如说1秒内,调用接口 ...
- 韦大仙--简单的monkey测试命令行操作及生成log日志保存
作中,在将apk交给软件测试人员去测试之前,不免要自己先自测,monkey自测是一个不错的选择! 步骤很简单: 1.测试用的手机与电脑连接好USB ,并且安装好驱动(我一般都是通过豌豆荚自动安装的)! ...
- 一篇文章让你了解GC垃圾回收器
简单了解GC垃圾回收器 了解GC之前我们首先要了解GC是要做什么的?顾名思义回收垃圾,什么是垃圾呢? GC回收的垃圾主要指的是回收堆内存中的垃圾对象. 从根对象出发,所有被引用的对象,都是存活对象 其 ...
- HTML 之 表单
关于HTML的表单 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset=&q ...
- 莱布尼兹三角形(C++)
[问题描述] 如下图所示的三角形,请编程输出图中排在第 n 行从左边数第 m 个位置上的数. [代码展示] # include<iostream># include<cstdio&g ...
- LeetCode 386——字典序的第 K 小数字
1. 题目 2. 解答 字典序排数可以看做是第一层节点分别为 1-9 的十叉树,然后我们在树上找到第 K 小的数字即可.因此,我们需要分别统计以 1-9 为根节点的每个树的节点个数.如果 K 小于当前 ...