博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Loj #3057. 「HNOI2019」校园旅行
阅读量:7014 次
发布时间:2019-06-28

本文共 3150 字,大约阅读时间需要 10 分钟。

Loj #3057. 「HNOI2019」校园旅行

某学校的每个建筑都有一个独特的编号。一天你在校园里无聊,决定在校园内随意地漫步。

你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你情不自禁的把周围每个建筑的编号都记了下来——但其实你没有真的记下来,而是把每个建筑的编号除以 \(2\) 取余数得到 \(0\)\(1\),作为该建筑的标记,多个建筑物的标记连在一起形成一个 \(01\) 串。

你对这个串很感兴趣,尤其是对于这个串是回文串的情况,于是你决定研究这个问题。

学校可以看成一张图,建筑是图中的顶点,而某些顶点之间存在无向边。对于每个顶点我们有一个标记(\(0\) 或者 \(1\))。每次你会选择图中两个顶点,你想知道这两个顶点之间是否存在一条路径使得路上经过的点的标记形成一个回文串

一个回文串是一个字符串使得它逆序之后形成的字符串和它自己相同,比如 \(010\)\(1001\) 都是回文串,而 \(01\)\(110\) 不是。注意长度为 \(1\) 的串总是回文串,因此如果询问的两个顶点相同,这样的路径总是存在。此外注意,经过的路径不一定为简单路径,也就是说每条边每个顶点都可以经过任意多次。

输入格式

第一行三个整数 \(n,m,q\),表示图中的顶点数和边数,以及询问数。

第二行为一个长度为 \(n\)\(01\) 串,其中第 \(n\) 个字符表示第 \(i\) 个顶点(即顶点 \(i\))的标记,点从 \(1\) 开始编号。

接下来 \(m\) 行,每一行是两个整数 \(u_i,v_i\),表示顶点 \(u_i\) 和顶点 \(v_i\) 之间有一条无向边,不存在自环或者重边。

接下来 \(q\) 行,每一行存在两个整数 \(x_i,y_i\),表示询问顶点 \(x_i\) 和顶点 \(y_i\) 的点之间是否有一条满足条件的路径。

输出格式

输出 \(q\) 行,每行一个字符串 YES,或者 NO。输出 YES 表示满足条件的路径存在,输出 NO 表示不存在。

样例

样例输入 1

5 4 2000104 51 34 22 53 51 3

样例输出 1

NOYES

样例说明 1

对于第一个询问,\(3\) 号点和 \(2\) 号点不连通, 因此答案为 NO

对于第二个询问,一条合法的路径是 \(1 \to 3\),路径上的标号形成的字符串为 \(00\)。注意合法路径不唯一。

样例输入 2

10 11 1000110111114 610 65 94 710 75 81 95 71 105 15 610 37 48 109 48 96 62 29 910 93 4

样例输出 2

NOYESYESNOYESYESYESYESYESNO
数据范围与提示

对于 \(30\%\) 的数据,\(1 \le m \le 10^4\)

对于 \(70\%\) 的数据,\(1\le n\le 3\times 10^3,1 \le m \le 5\times 10^4\)

对于 \(100\%\) 的数据,\(1 \le n \le 5\times 10^3, 1 \le m \le 5\times 10^5, 1 \le q \le 10^5\)

首先很容易想到暴力两边并行\(DFS\)的做法,这样复杂度是\(O(m^2)\)的。

然后考虑优化建边。

对于同种颜色的联通块,如果它是个二分图就保留一个生成树边就行了。因为对于一条非树边,它一定在一个偶环上。假设现在走到\(a,b\),然后\(a\)要走非树边,那么我们实际上随便走一个环,然后\(b\)就找一个相邻的同色节点(如果有的话)反复横跳,因为是偶环,所以是等价的。

如果不是一个二分图,那么我们依然保留非树边,然后随便从一个点连一个子环。因为我们可以改变路径的奇偶。

对于两边颜色不同的边,他们组成的图一定是一个二分图。

代码:

#include
#define ll long long#define N 5005#define M 1000005#define Q 100005using namespace std;inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}int n,m,q;struct road { int to,nxt;}s[M<<1];int h[N],cnt;void add(int i,int j) { s[++cnt]=(road) {j,h[i]};h[i]=cnt;}vector
e[N];bool ans[N][N];char str[N];int col[N];#define pr pair
#define mp(a,b) make_pair(a,b)queue
que;vector
vec;void bfs() { for(int i=0;i
b) swap(a,b); ans[a][b]=1; que.push(mp(a,b)); } while(!que.empty()) { int x=que.front().first,y=que.front().second; que.pop(); for(int i=h[x];i;i=s[i].nxt) { for(int j=h[y];j;j=s[j].nxt) { int a=s[i].to,b=s[j].to; if(col[a]!=col[b]) continue ; if(a>b) swap(a,b); if(!ans[a][b]) { ans[a][b]=1; que.push(mp(a,b)); } } } }}int f[N];int Getf(int v) {return v==f[v]?v:f[v]=Getf(f[v]);}int flag;int w[N];void dfs(int v,int Col) { w[v]=Col; for(int i=0;i
b) swap(a,b); if(col[a]==col[b]) vec.push_back(mp(a,b)); } for(int i=1;i<=n;i++) vec.push_back(mp(i,i)); memset(w,-1,sizeof(w)); for(int i=1;i<=n;i++) { if(w[i]!=-1) continue ; flag=1; dfs(i,0); if(!flag) add(i,i); } bfs(); while(q--) { a=Get(),b=Get(); if(a>b) swap(a,b); if(ans[a][b]) cout<<"YES\n"; else cout<<"NO\n"; } return 0;}

转载于:https://www.cnblogs.com/hchhch233/p/10685592.html

你可能感兴趣的文章
JDK1.7中HashMap底层实现原理
查看>>
mvc简介
查看>>
005_控制器和动作
查看>>
[struts]数据标签的使用
查看>>
Nginx
查看>>
小KING教你做android项目(二)---实现登陆页面并跳转和简单的注册页面
查看>>
Paint.FontMetrics
查看>>
初步理解require.js模块化编程
查看>>
计算机网络(一)
查看>>
asyncsocket的用法
查看>>
【贪心】HDU 1257
查看>>
nodejs 解决跨域
查看>>
04 变量和参数介绍
查看>>
C# 关于LINQ基础随笔
查看>>
ASP.NET MVC 3 Razor 视图引擎 基本语法
查看>>
C# 关于XML的简单操作实例
查看>>
ggplot2:画世界地图和中国地图 合并数据 增添信息 标记
查看>>
火狐开发----Web开发者工具
查看>>
修改mysql表操作
查看>>
简单背包问题
查看>>