日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

[HNOI2019]校园旅行

發布時間:2023/12/2 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [HNOI2019]校园旅行 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目

過于神仙啊,抄題解.jpg

首先\(n\)并不是很大啊,我們可以直接用\(f_{i,j}\)表示\(i\)\(j\)是否存在一個回文路徑

對于一條回文路徑,如果在兩端分別添加一個相同的字符,那么仍然是一個回文路徑,于是我們可以利用這個來打一個暴力\(bfs\)

就像這樣

while(!q[0].empty()) {int x=q[0].front(),y=q[1].front();q[0].pop(),q[1].pop();for(re int i=0;i<v[x].size();i++)for(re int j=0;j<v[y].size();j++) {int xx=v[x][i],yy=v[y][j];if(xx>yy) std::swap(xx,yy);if(S[xx]!=S[yy]||f[xx][yy]) continue;f[xx][yy]=dp[xx][yy]=1;q[0].push(xx),q[1].push(yy);}}

非常顯然這個復雜度一點也不科學,卡滿就是\(O(m^2)\)的,肯定是要\(T\)

但是\(n\)卻不是很大,能不能讓邊數減小一點呢

之后就不會啦,愉快地抄題解

首先我們注意到一個問題,就是我們只需要關注奇偶性就好了,因為我們可以來回走一條邊使得長度增加,但是并不能改變奇偶性

之后我也不知道為什么通過這一點就想到了二分圖

我們把邊分成兩類,一類是連接相同顏色點的邊,一類是連接不同顏色點的邊

我們考慮一個連通塊,這個連通塊僅由相同顏色的點構成,顯然這個連通塊里的邊都是第一類邊

如果這個連通塊是一個二分圖,由于二分圖不存在奇環,對于任意兩個點,所有連接這兩個點的路徑的奇偶性都是一樣的

由于我們也只關注奇偶性,所以只需要對這個二分圖搞出來一棵生成樹即可

如果這個聯通塊不是一個二分圖,那么就一定存在至少一個奇環,那么我們就可以通過走這個奇環使得路徑的奇偶性改變

我們需要讓邊的數量盡量少,那么只需要求出來一棵有奇環的基環樹即可

這些我們都能通過\(dfs\)來完成

對于第二類邊,只考慮這些邊的話整張圖就是一個二分圖,于是我們還是對這些邊求一個生成樹即可

最后我們發現我們這張圖的邊數已經和\(n\)同級了,于是我們直接上最開始的那個暴力,復雜度就是\(O(n^2)\)

代碼

#include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define re register inline int read() {char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x; } const int maxn=5e3+5; std::vector<int> v[maxn]; std::queue<int> q[2]; struct E{int v,nxt;}e[1000005]; int n,m,Q,num,tot,flag; char S[maxn]; int f[maxn][maxn],dp[maxn][maxn],vis[maxn],fa[maxn],sz[maxn],pre[maxn]; int head[maxn],a[500005],b[500005]; inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num; } void dfs(int x,int fa) {vis[x]=1;for(re int i=head[x];i;i=e[i].nxt) {if(S[e[i].v]!=S[x]||fa==e[i].v) continue;if(vis[e[i].v]&&S[e[i].v]==S[x]&&!flag) {if(!(pre[e[i].v]^pre[x])) v[x].push_back(e[i].v),v[e[i].v].push_back(x),flag=1;continue;}v[x].push_back(e[i].v);v[e[i].v].push_back(x);pre[e[i].v]=pre[x]^1;dfs(e[i].v,x);} } inline int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);} inline void merge(int x,int y) {if(sz[x]<sz[y]) fa[y]=x,sz[y]+=sz[x];else fa[x]=y,sz[x]+=sz[y]; } int main() {n=read(),m=read(),Q=read();scanf("%s",S+1);for(re int x,y,i=1;i<=m;i++) {x=read(),y=read(),add(x,y),add(y,x);if(S[x]!=S[y]) a[++tot]=x,b[tot]=y;}for(re int i=1;i<=n;i++) {if(vis[i]) continue;flag=0;dfs(i,0);}for(re int i=1;i<=n;i++) fa[i]=i,sz[i]=1;for(re int i=1;i<=tot;i++) {int xx=find(a[i]),yy=find(b[i]);if(xx==yy) continue;merge(xx,yy);v[a[i]].push_back(b[i]);v[b[i]].push_back(a[i]);}for(re int i=1;i<=n;i++) f[i][i]=dp[i][i]=1,q[0].push(i),q[1].push(i);for(re int i=1;i<=n;i++) for(re int j=0;j<v[i].size();j++) {int x=i,y=v[i][j];if(x>y) std::swap(x,y);if(S[x]!=S[y]||f[x][y]) continue;f[x][y]=dp[x][y]=1,q[0].push(x),q[1].push(y);}while(!q[0].empty()) {int x=q[0].front(),y=q[1].front();q[0].pop(),q[1].pop();for(re int i=0;i<v[x].size();i++)for(re int j=0;j<v[y].size();j++) {int xx=v[x][i],yy=v[y][j];if(xx>yy) std::swap(xx,yy);if(S[xx]!=S[yy]||f[xx][yy]) continue;f[xx][yy]=dp[xx][yy]=1;q[0].push(xx),q[1].push(yy);}}for(re int x,y,i=1;i<=Q;i++) {x=read(),y=read();if(x>y) std::swap(x,y);puts(dp[x][y]?"YES":"NO");}return 0; }

轉載于:https://www.cnblogs.com/asuldb/p/10803482.html

總結

以上是生活随笔為你收集整理的[HNOI2019]校园旅行的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。