1. 程式人生 > >Bzoj P2054 瘋狂的饅頭 | 並查集

Bzoj P2054 瘋狂的饅頭 | 並查集

name com 顏色 return mes std 存在 處理 鏈接

題目鏈接

思路:因為每次染色都會將某些饅頭的顏色徹底更改,所以每個饅頭的最終的顏色其實是由最後一次染色決定的,那麽我們只考慮最後一次染色即可。對此,我們可以從後往前倒著染色,當目前的染色區間中存在白色饅頭時,就將其染成當前的顏色,對於已經染過色的饅頭則不處理,因為當前這一次染色已經不是其最後一次染色了,其最終顏色已經確定了。

對以上思路,考慮用經過路徑壓縮優化的並查集來維護在每個饅頭右側的、距離最近的、未染色的饅頭的位置,以減小時間復雜度。

總時間復雜度O(m+n)。

代碼:

#include<iostream>
#include<cstdio>
    using
namespace std; int c[1000005],f[1000005]; int find(int x) { if(f[x]==x) return x; return f[x]=find(f[x]);//路徑壓縮 } int main() { int n=0,m=0,p=0,q=0; scanf("%d%d%d%d",&n,&m,&p,&q); for(int i=1;i<=n+1;i++) f[i]=i;//初始化 for(int i=m;i>=1;i--) {
int l=(i*p+q)%n+1,r=(i*q+p)%n+1; if(l>r) swap(l,r); for(int k=l;;) { int fx=find(k); k=f[fx];//向右找最近的未染色的饅頭進行染色 if(k>r) break;//如果超過了染色區間範圍則退出 c[k]=i;//染色 f[fx]=find(k+1);//向右合並,得出下一個最近的、在右邊的未染色饅頭的位置(畫畫圖就明白了)
} } for(int i=1;i<=n;i++) printf("%d\n",c[i]); return 0; }

Bzoj P2054 瘋狂的饅頭 | 並查集