题面传送门
启发式合并大法吼啊。
优雅的暴力。
暴力:遍历整个数组去修改,时间复杂度
换一个思路暴力:对于每个
维护一个队列,每次把两个队列合并。时间复杂度还是
那可不能够优化一下呢?
每次咱们不能把小的合并到大的上面去吗,这样能够减小点常数。
等等,你肯定是常数?
彷佛能够算一算复杂度,对于每个初始队列,他最多会被合并
次,时间复杂度上界
。
那合并完以后怎么放回去呢?
都暴力成这样了,继续暴力不就行了吗?
代码实现:html
#include<cstdio> #include<cstring> using namespace std; int n,m,k,a[1000039],size[1000039],x,y,ans,tot,pus,h[1000039],head,now,cur; struct yyy{ int to,z; }f[1000039],tmp; inline void add(int x,int y){ f[++head]=(yyy){y,h[x]}; h[x]=head; size[x]++; } inline void read(int &x){ char s=getchar();x=0; while(s<'0'||s>'9') s=getchar(); while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar(); } inline void print(int x){ if(x>9) print(x/10); putchar(x%10+48); } int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); memset(h,-1,sizeof(h)); register int i; read(n);read(m);read(k); for(i=1;i<=n;i++) read(a[i]),add(a[i],i); for(i=1;i<=k;i++){ read(x);read(y); if(x==y) continue; if(size[x]>size[y]){ size[x]+=size[y]; cur=h[y]; while(cur!=-1){ tmp=f[cur]; f[cur].z=h[x]; h[x]=cur; cur=tmp.z; } size[y]=size[x]; h[y]=h[x]; h[x]=-1; size[x]=0; } else{ size[y]+=size[x]; cur=h[x]; while(cur!=-1){ tmp=f[cur]; f[cur].z=h[y]; h[y]=cur; cur=tmp.z; } h[x]=-1;size[x]=0; } } for(i=1;i<=m;i++){ cur=h[i]; while(cur!=-1){ tmp=f[cur]; a[tmp.to]=i; cur=tmp.z; } } for(i=1;i<=n;i++) print(a[i]),putchar(' '); }