博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[HNOI2019]校园旅行
阅读量:6283 次
发布时间:2019-06-22

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

题目描述

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

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

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

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

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

题解

非常巧妙的一道题。

先考虑朴素的做法,记\(dp[l][r]\)表示\(l\)\(r\)能否构成一个回文串,这个可以用\(BFS\)扩展。

分析一下复杂度,发现它是\(m^2\)的。

考虑到边数很多而点数很少,所以考虑把不必要的边去掉。

考虑连接颜色相同的边构成的联通块,然后有结论,如果这是一个二分图,那么我们只需要保留其中的一颗生成树,如果不是,那么给其中的一个点加上一个自环就好了。

那么对于连接两种颜色的边也一样,因为它本身是一个二分图,所以就保留一个生成树就好了。

至于原因,考虑如果是一个二分图,从\((x,y)\)扩展到\((x',y')\),那么\(x\)走的步数和\(y\)走的步数的奇偶性是一样的,所以我们需要证明当走的步数足够大的时候,只要奇偶性不变,从\(x\)一定能够走到\(x'\),

因为是二分图,我们多的边可以来回走就好了。

如果不是二分图,我们可以通过自环来调整奇偶性。

这样我们就把边数调整到了\(O(n)\)级别。

代码

#include
#define N 5009using namespace std;typedef long long ll;int n,m,Q,head[N],tot,f[N];char s[N];bool ans[N][N],co[N],tag[N];inline ll rd(){ ll x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x;}struct node{int x,y;};vector
vec[2],nw;vector
::iterator it;queue
q;struct edge{int n,to;}e[N*N];inline void add(int u,int v){ e[++tot].n=head[u];e[tot].to=v;head[u]=tot; e[++tot].n=head[v];e[tot].to=u;head[v]=tot;}int find(int x){ if(x==f[x])return x; int xx=find(f[x]); co[x]^=co[f[x]]; return f[x]=xx;}int main(){ n=rd();m=rd();Q=rd(); scanf("%s",s+1); int x,y; for(int i=1;i<=m;++i){ x=rd();y=rd(); if(s[x]==s[y]){ vec[s[x]-'0'].push_back(node{x,y}); ans[x][y]=ans[y][x]=1;q.push(node{x,y}); } else nw.push_back(node{x,y}); } for(int i=1;i<=n;++i)f[i]=i,co[i]=tag[i]=0; for(it=vec[0].begin();it!=vec[0].end();++it){ node x=*it; int xx=find(x.x),yy=find(x.y); if(xx!=yy){ f[xx]=yy;tag[yy]|=tag[xx]; co[xx]=co[x.x]^co[x.y]^1; add(x.x,x.y); } else if(co[x.x]==co[x.y]&&!tag[yy]){ tag[yy]=1; add(x.x,x.y); } } for(it=vec[1].begin();it!=vec[1].end();++it){ node x=*it; int xx=find(x.x),yy=find(x.y); if(xx!=yy){ f[xx]=yy;tag[yy]|=tag[xx]; co[xx]=co[x.x]^co[x.y]^1; add(x.x,x.y); } else if(co[x.x]==co[x.y]&&!tag[yy]){ tag[yy]=1; add(x.x,x.y); } } for(int i=1;i<=n;++i)f[i]=i; for(it=nw.begin();it!=nw.end();++it){ node x=*it; int xx=find(x.x),yy=find(x.y); if(xx!=yy){ f[xx]=yy; add(x.x,x.y); } } for(int i=1;i<=n;++i)ans[i][i]=1,q.push(node{i,i}); while(!q.empty()){ node x=q.front();q.pop(); for(int i=head[x.x];i;i=e[i].n) for(int j=head[x.y];j;j=e[j].n){ int v1=e[i].to,v2=e[j].to; if(ans[v1][v2]||s[v1]!=s[v2])continue; ans[v1][v2]=ans[v2][v1]=1; q.push(node{v1,v2}); } } while(Q--){ x=rd();y=rd(); puts(ans[x][y]?"YES":"NO"); } return 0;}

转载于:https://www.cnblogs.com/ZH-comld/p/10819934.html

你可能感兴趣的文章
Maven 插件
查看>>
初探Angular6.x---进入用户编辑模块
查看>>
计算机基础知识复习
查看>>
【前端词典】实现 Canvas 下雪背景引发的性能思考
查看>>
大佬是怎么思考设计MySQL优化方案的?
查看>>
<三体> 给岁月以文明, 给时光以生命
查看>>
Android开发 - 掌握ConstraintLayout(九)分组(Group)
查看>>
springboot+logback日志异步数据库
查看>>
Typescript教程之函数
查看>>
Android 高效安全加载图片
查看>>
vue中数组变动不被监测问题
查看>>
3.31
查看>>
类对象定义 二
查看>>
收费视频网站Netflix:用户到底想要“点”什么?
查看>>
MacOS High Sierra 12 13系统转dmg格式
查看>>
关于再次查看已做的多选题状态逻辑问题
查看>>
动态下拉菜单,非hover
查看>>
政府安全资讯精选 2017年第十六期 工信部发布关于规范互联网信息服务使用域名的通知;俄罗斯拟建立备用DNS;Google打击安卓应用在未经同意情况下收集个人信...
查看>>
简单易懂的谈谈 javascript 中的继承
查看>>
iOS汇编基础(四)指针和macho文件
查看>>