bzoj1483 [HNOI2009]梦幻布丁
水题。网上都说是什么链表的启发式合并,我也不太明白,反正我就写了个链表,然后也没什么启发式合并,就那么暴力合并就行了,速度也不慢。
我们记录每个位置的下一个和它一样的颜色的位置next[i],对于每个i如果i+1!=next[i],那么i处会构成一个颜色短,一开始先这么统计出来,往后只可能增加,不可能减少。另外记录每个颜色的起始位置。
合并的时候把两个颜色(x,y)都扫一遍,遇到相邻的x,y就链上,然后如果出现了i+1==next[i]就把答案数减1。注意最后保证x的信息全都复制到了y上才行。
pudding
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #define maxn 1200000 7 using namespace std; 8 9 int st[maxn],next[maxn],col[maxn],last[maxn]; 10 int n,m,ans; 11 12 void merge(int x,int y) 13 { 14 if (x==y) return ; 15 int i=st[x],j=st[y]; 16 if (st[x]<st[y]||st[y]==0) st[y]=st[x]; 17 st[x]=0; 18 int k; 19 while (i&&j) 20 { 21 if (i<j) 22 { 23 while (next[i]<j&&next[i]) i=next[i]; 24 if (j==i+1) ans--; 25 k=next[i];next[i]=j; 26 i=k; 27 } 28 else 29 { 30 while (next[j]<i&&next[j]) j=next[j]; 31 if (i==j+1) ans--; 32 k=next[j];next[j]=i; 33 j=k; 34 } 35 } 36 } 37 38 int main() 39 { 40 //freopen("pudding.in","r",stdin); 41 //freopen("pudding.out","w",stdout); 42 scanf("%d%d",&n,&m); 43 for (int i=1;i<=n;i++) scanf("%d",&col[i]); 44 for (int i=1;i<=n;i++) 45 { 46 if (!last[col[i]]) st[col[i]]=i; 47 else next[last[col[i]]]=i; 48 last[col[i]]=i; 49 } 50 for (int i=1;i<=n;i++) 51 if (next[i]!=i+1) ans++; 52 int sign,x,y; 53 for (int i=1;i<=m;i++) 54 { 55 scanf("%d",&sign); 56 if (sign==2) printf("%d\n",ans); 57 else 58 { 59 scanf("%d%d",&x,&y); 60 merge(x,y); 61 } 62 } 63 return 0; 64 }
AC without art, no better than WA !