1. 程式人生 > 實用技巧 >洛谷 P2391.白雪皚皚 (並查集,思維)

洛谷 P2391.白雪皚皚 (並查集,思維)

  • 題意:有\(n\)個點,對這些點進行\(m\)次染色,第\(i\)次染色會把區間\((i*p+q)\ mod\ N+1\)\((i*q+p)\ mod\ N+1\)之間的點染成顏色\(i\),問最後這\(n\)個點的顏色.

  • 題解:我們可以反著從第\(m\)次開始染,因為後面的會把前面點的顏色覆蓋,所以倒著來的話,下一次染的時候就可以不用考慮已經染過的區間了,那麼我們怎麼維護染過的區間呢?我們可以把這些區間看成是一些連通塊,所以可以用並查集來對區間進行維護,讓區間內的所有點均指向它的右端點,具體操作看程式碼吧.

  • 程式碼:

    #include <iostream>
    #include <iomanip>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <map>
    #include <set>
    #include <unordered_set>
    #include <unordered_map>
    #define ll long long
    #define db double
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e7 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    int lcm(int a,int b){return a/gcd(a,b)*b;}
    
    inline int read()
    {
        int X=0; bool flag=1; char ch=getchar();
        while(ch<'0'|ch>'9') {if(ch=='-') flag=0; ch=getchar();}
        while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
        if(flag) return X;
        return ~(X-1);
    }
    
    int n,m,p,q;
    int P[N];
    int color[N];
    
    int find(int x){
        if(P[x]!=x) P[x]=find(P[x]);
        return P[x];
    }
    
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        cin>>n>>m>>p>>q;
    
        rep(i,1,n) P[i]=i;
    
        P[n+1]=n+1;
    
        per(i,m,1){
            int l=(i*p+q)%n+1;
            int r=(i*q+p)%n+1;
            if(l>r) swap(l,r);
    
            l=find(l);     //找左端點所在區間集合的右端點
    
            while(l<=r){
                color[l]=i;
                P[l]=l+1;     //每次讓當前點的祖宗是它下一個點
                l=find(P[l+1]); //找下一個點的祖宗
            }
        }
    
        rep(i,1,n) cout<<color[i]<<'\n';
    
        return 0;
    }