At_abc380_e 1D Bucket Tool 题解

· · 题解

思路:

用并查集合并同色块,用链表维护每个同色块的前一个和后一个同色块,再维护一下每个同色块的大小以及每种颜色的数量即可。

可以用并查集的树根代表每个同色块,这样每次修改只需修改树根即可。

若该同色块修改后与其前驱或后继同色,则把他们合并。具体的,在并查集中合并把两个块合并,随后把不作为树根的那个块从链表中删除。

Code:

#include<bits/stdc++.h>
//#define int long long
#define rd read<int>()
#define rdl read<ll>()
#define pb emplace_back
#define mkp make_pair
#define fr first
#define se second
#define Endl putchar('\n')
#define Space putchar(' ')
using namespace std;
using pii=pair<int,int>;
typedef long long ll;
const int mod=998244353,inf=0x3f3f3f3f;
const ll Inf=0x3f3f3f3f3f3f3f3f;
template<class T> inline T read(){
    T s=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
    return s*f;
}
template<typename T> inline void write(T x){
    static int st[40],Top;
    if(x<0){putchar('-');x=-x;}
    if(!x)putchar('0');
    while(x){st[++Top]=x%10;x/=10;}
    while(Top){putchar(st[Top--]^'0');}
}
inline char readc(){
    char c=getchar();
    while(c=='\n'||c=='\r'||c==' '||c==EOF)c=getchar();
    return c;
}
const int N=5e5+10;
int n,q,f[N],sz[N],col[N],a[N],pre[N],nxt[N]; 
int find(int x){
    if(x==f[x])return x;
    return f[x]=find(f[x]);
}
void solve(){
    n=rd,q=rd;
    for(int i=1;i<=n;i++){
        f[i]=a[i]=i;sz[i]=col[i]=1;
        pre[i]=i-1;nxt[i]=i+1;
    }
    while(q--){
        int op=rd,x=rd;
        if(op==2){
            write(col[x]),Endl;
            continue;
        }
        int c=rd;
        x=find(x);
        col[a[x]]-=sz[x];
        a[x]=c;
        col[c]+=sz[x];
        pre[x]=find(pre[x]);
        nxt[x]=find(nxt[x]);
        if(pre[x]&&a[pre[x]]==c){
            f[pre[x]]=x;
            sz[x]+=sz[pre[x]];
            pre[x]=pre[pre[x]];
        }
        if(nxt[x]<=n&&a[nxt[x]]==c){
            f[nxt[x]]=x;
            sz[x]+=sz[nxt[x]];
            nxt[x]=nxt[nxt[x]];
        }
    }
}
signed main(){
    int T=1;
//  T=read<signed>();
    while(T--){
        solve();
    }
    return 0;
}