萌新刚学分块口胡用并查集解决,给每个块内每种值分别开点,并给每个值开点连向它的值。
整块修改如果 y 存在就将 x 值的点连到 y ,否则把代表 x 的点变成代表 y 的点。散块如果没有 y 新建节点,然后暴力连边。代码如下:
#include<bits/stdc++.h>
using namespace std;
int fa[1000005],pos[500][105],d[200005],k,n,tot;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline int rs(int i){return min(n,k*i);}
inline int ls(int i){return k*(i-1)+1;}
int a[200005];
int main()
{
int q,l,r,x,y;cin>>n;k=sqrt(n);tot=n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);d[i]=(i-1)/k+1;
if(!pos[d[i]][a[i]]) pos[d[i]][a[i]]=++tot,fa[tot]=tot;
fa[i]=pos[d[i]][a[i]];
}
cin>>q;while(q--)
{
scanf("%d%d%d%d",&l,&r,&x,&y);
if(x==y) continue;int L=d[l],R=d[r];
if(L==R)
{
if(!pos[L][y]||fa[pos[L][y]]!=pos[L][y]) pos[L][y]=++tot,fa[tot]=tot;
for(int i=l;i<=r;i++) if(find(i)==pos[L][x]) fa[i]=pos[L][y];
continue;
}
for(int i=L+1;i<=R-1;i++)
{
if(!pos[i][x]) continue;
if(!pos[i][y]||fa[pos[i][y]]!=pos[i][y]) pos[i][y]=pos[i][x],pos[i][x]=0;
else fa[pos[i][x]]=pos[i][y];
}
if(!pos[L][y]||fa[pos[L][y]]!=pos[L][y]) pos[L][y]=++tot,fa[tot]=tot;
if(!pos[R][y]||fa[pos[R][y]]!=pos[R][y]) pos[R][y]=++tot,fa[tot]=tot;
for(int i=l;i<=rs(L);i++) if(find(i)==pos[L][x]) fa[i]=pos[L][y];
for(int i=ls(R);i<=r;i++) if(find(i)==pos[R][x]) fa[i]=pos[R][y];
}
for(int i=1;i<=n;i++)
{
int xx=find(i);
for(int j=1;j<=100;j++)
{
if(pos[d[i]][j]==xx)
{
printf("%d ",j);
break;
}
}
}
return 0;
}
QAQ