Moya_Rao
2024-11-17 17:51:48
给你
现在有
1 x c
:表示把编号为 2 c
:输出当前颜色为 赛时硬控我一直到结束,最后题目理解出错,思路偏离正解很远很远,第二天再来一看,恍然大悟,拿着第一次的错误代码一调,就过了。不得不说,我还只是一只菜鸡呀,需要多练练。
现在我们回到正题。
其实上,
那么我们要怎么合并这些连通块呢?很简单,记录一下这个连通块的左端点和右端点,因为这道题目很特殊,它的一个连通块定是一个区间。合并的时候,就看看当前这个连通块的左端点左边的那个格子(如果存在),所处的那个集合,可不可以经过这次涂色把它们连成一个连通块。还要看当前这个连通块的右端点右边的那个格子(如果存在),所处的那个集合,是不是也可以经过这次涂色把它们连成一个连通块。这些步骤都可以在进行操作
操作
是不是还挺简单滴?
这份代码是加了注释的哟!
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+5;
struct node{int l,r,c;}p[N];
//l 和 r 分别是这个集合的两个端点,c 是这个集合目前的颜色
//当然了,只有在 i 是某个集合的代表物时,p[i] 里的数据才是准的
int n,Q,fa[N],cnt[N];//fa 是父亲,cnt 是每种颜色当前个数
int FF(int u){return fa[u]==u?u:fa[u]=FF(fa[u]);}
//经过了路径压缩的找代表物代码,还用了三目运算符(这个总应该懂吧)缩短代码长度
int main(){
cin>>n>>Q;
for(int i=1;i<=n;i++)p[i]={i,i,i},fa[i]=i,cnt[i]=1;//初始化
while(Q--){
int opt;cin>>opt;//opt 表示操作编号
if(opt==1){//如果是操作 1
int id,co;cin>>id>>co;//输入编号以及颜色
int fid=FF(id);//首先找到当前这个 id 所在集合的代表物
cnt[p[fid].c]-=p[fid].r-p[fid].l+1;
//fid 这个集合的所有格子都不再是这个颜色了,要从 cnt 里减去
p[fid].c=co;//更换颜色
cnt[p[fid].c]+=p[fid].r-p[fid].l+1;
//fid 这个集合的所有格子全都变成这个新的颜色了,cnt 要加上
if(p[fid].l!=1){//如果存在左边的集合
int fsm=FF(p[fid].l-1);//左边的集合代表物是谁
if(p[fid].c==p[fsm].c)fa[fsm]=fid,p[fid].l=p[fsm].l;
//左边的集合与当前集合颜色相同,合并为一个
}
if(p[fid].r!=n){//如果存在右边的集合
int fbg=FF(p[fid].r+1);//右边的集合代表物是谁
if(p[fid].c==p[fbg].c)fa[fbg]=fid,p[fid].r=p[fbg].r;
//右边的集合与当前集合颜色相同,合并为一个
}
}
else{//否则是操作 2
int c;cin>>c;
cout<<cnt[c]<<"\n";//直接报告答案即可
}
}
return 0;
}