题解:【MX-X10-T5】[LSOT-4] Masuko or Haru?

前言

好题,在英语课上想出来的。

但是这个评蓝是不是星战得降绿了?

思路分析

首先差分原序列,把区间修改变成两个单点修改。

然后考虑什么时候两个 01 串是等价的。

我们希望把两个 01 串不同的位置变成相同的。不难发现,如果我们将一对单点修改之间连边,那么如果两个不同的位置之间联通,那么我们就可以沿着边一路修改过去,满足只有路径端点改变。

举一个例子,如果我们两个不同的点是 \(x,y\),它们在图上的一条路径是 \(x \to a\to b\to y\),那我们就依次修改 \((x,a),(a,b),(b,y)\),这样 \(a,b\) 没有变化,\(x,y\) 被修改了。

所以,我们得出结论,两个 01 串等价,当且仅当图上各个联通块内,不同的位置的个数为偶数。

我们对这个结论进行一点等价变换:两个 01 串等价,当且仅当图上各个连通块内,异或和相等。

第二个结论可以直接用异或哈希维护。我们用并查集维护联通块,每个根节点分别记录 \(n\) 个 01 串在这个联通块内的异或和。我们将每个根节点随机赋一个权值,每一行维护根节点异或和为 \(1\) 的,随机权值异或和,两个 01 串等价当且仅当它们维护的异或和相等。

注意特判 \(m+1\) 列的问题。如果不判会获得 17 分的高分。

复杂度 \(O(nm+m\alpha(m))\)

代码实现

#include<bits/stdc++.h>
#define int long long
using namespace std;
char ch;
int n,m,q,l,r,x,y,op,a[10000005],b[10000005];
int fa[5000005],rnd[5000005],has[5000005];
vector<int> val[5000005];
void init(){
    for(int i=1;i<=m;i++){
        fa[i]=i;
        rnd[i]=rand()*rand();
        val[i].push_back(0);
        for(int j=1;j<=n;j++){
            val[i].push_back(a[(j-1)*m+i]);
            has[j]^=a[(j-1)*m+i]*rnd[i];
        }
    }
    fa[m+1]=m+1;
    for(int j=0;j<=n;j++){
        val[m+1].push_back(0);
    }
}
int find(int x){
    if(fa[x]==x) return x;
    else return fa[x]=find(fa[x]);
}
void merge(int x,int y){
    x=find(x);
    y=find(y);
    if(x==y) return;
    fa[y]=x;
    for(int i=1;i<=n;i++){
        if(val[x][i]) has[i]^=rnd[x];
        if(val[y][i]) has[i]^=rnd[y];
        val[x][i]^=val[y][i];
        if(val[x][i]) has[i]^=rnd[x];
    }
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m>>q;
    for(int i=1;i<=n*m;i++){
        cin>>ch;
        a[i]=ch-'0';
    }
    for(int i=1;i<=n;i++){
        b[(i-1)*m+1]=a[(i-1)*m+1];
        for(int j=2;j<=m;j++){
            b[(i-1)*m+j]=a[(i-1)*m+j-1]^a[(i-1)*m+j];
        }
    }
    memcpy(a,b,sizeof(a));
    init();
    for(int i=1;i<=q;i++){
        cin>>op;
        if(op==1){
            cin>>l>>r;
            merge(l,r+1);
        }else{
            cin>>x>>y;
            if(has[x]==has[y] || (has[x]^has[y])==rnd[find(m+1)]) cout<<"Masuko"<<'\n';
            else cout<<"Haru"<<'\n';
        }
    }
}
posted @ 2025-04-11 16:03  _Kenma  阅读(23)  评论(0)    收藏  举报