您的位置:首页 > 其它

BZOJ 1483 HNOI2009 梦幻布丁 名单+启示录式的合并

2015-08-26 11:14 471 查看
标题效果:特定n布丁。每个人都有一个颜色布丁,所有的布丁反复有一定的颜色变化的颜色,颜色反复询问的段数

数据范围:n<=10W 色彩数<=100W

启发式合并名单0.0 从来不写清楚 实际上打开列表记录每个颜色的位置,链看看两边是不是长链的颜色即可

只是交换比較麻烦0.0 要开个数组记录每一个数字代表的真实颜色 交换时把数组的这两个位置也交换下就能够了

注意用过的垃圾不要留在原位 size合并掉就清零 head合并走了就弄成NULL 不然会挂 强迫症的福音啊

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 1001001
using namespace std;
struct abcd{
abcd *next;
int pos;
}*head[M];
int n,m,ans,a[M];
int f[M],size[M];
inline void Add(int x,int y)
{
abcd *temp=new abcd;
temp->pos=y;
temp->next=head[x];
head[x]=temp;
}
inline void Merge(int x,int y)
{
abcd *temp;

if(x==y)
return ;

if(size[f[x]]>size[f[y]])
swap(f[x],f[y]);
x=f[x];y=f[y];

if(!head[x])
return ;

for(temp=head[x];temp;temp=temp->next)
{
if(a[temp->pos-1]==y) --ans;
if(a[temp->pos+1]==y) --ans;
}
for(temp=head[x];temp;temp=temp->next)
a[temp->pos]=y;
for(temp=head[x];temp->next;temp=temp->next);

temp->next=head[y];head[y]=head[x];head[x]=0x0;
size[y]+=size[x];size[x]=0;

}
int main()
{
int i,p,x,y;
cin>>n>>m;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]!=a[i-1])
++ans;
Add(a[i],i);
f[a[i]]=a[i];
size[a[i]]++;
}
for(i=1;i<=m;i++)
{
scanf("%d",&p);
if(p==1)
{
scanf("%d%d",&x,&y);
Merge(x,y);
}
else
printf("%d\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: