bzoj1483

bzoj1483

题意:

N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色。

题解:

给每个颜色建一个链表。先预处理出答案,然后每次修改颜色时将两个链表合并,同时将修改后颜色对答案的贡献重新计算(如果两个节点的位置相差大于1说明中间有一段颜色,将贡献+1)。链表合并时用启发式合并(就是将小的拆了依次插入到大的里面),复杂度O(nlog2n)(均摊复杂度,玄学)。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define M 1000010
 6 #define N 100010
 7 using namespace std;
 8
 9 int ans,head[M],last[N],next[N],comb[M],sz[M],n,m;
10 int main(){
11     scanf("%d",&n); scanf("%d",&m); int a,b=0; ans=0;
12     memset(sz,0,sizeof(sz)); memset(comb,0,sizeof(comb)); memset(head,0,sizeof(head));
13     inc(i,1,n){
14         scanf("%d",&a); if(a!=b)ans++,comb[a]++;
15         next[i]=head[a]; last[head[a]]=i; head[a]=i; sz[a]++; b=a;
16     }
17     inc(i,1,m){
18         int a1; scanf("%d",&a1); if(a1==2)printf("%d\n",ans);
19         if(a1==1){
20             int a2,a3; scanf("%d%d",&a2,&a3); if(a2==a3)continue;
21             if(head[a2]==0)continue;
22             else if(head[a3]==0)head[a3]=head[a2],sz[a3]=sz[a2],comb[a3]=comb[a2],head[a2]=sz[a2]=comb[a2]=0;
23             else{
24                 if(sz[a2]<sz[a3]){
25                     int a4=head[a2],a6=head[a3];
26                     while(a4){
27                         int a5=next[a4];
28                         for(;a4<a6&&next[a6]>0;a6=next[a6]);
29                         if(a4<a6)next[a6]=a4,last[a4]=a6,next[a4]=0;
30                         else if(last[a6]==0)last[a4]=0,next[a4]=a6,last[a6]=a4,head[a3]=a4;
31                         else next[last[a6]]=a4,last[a4]=last[a6],next[a4]=a6,last[a6]=a4;
32                         sz[a3]++; a4=a5;
33                     }
34                     sz[a2]=head[a2]=0;
35                 }else{
36                     int a4=head[a3],a6=head[a2];
37                     while(a4){
38                         int a5=next[a4];
39                         for(;a4<a6&&next[a6]>0;a6=next[a6]);
40                         if(a4<a6)next[a6]=a4,last[a4]=a6,next[a4]=0;
41                         else if(last[a6]==0)last[a4]=0,next[a4]=a6,last[a6]=a4,head[a2]=a4;
42                         else next[last[a6]]=a4,last[a4]=last[a6],next[a4]=a6,last[a6]=a4;
43                         sz[a2]++; a4=a5;
44                     }
45                     head[a3]=head[a2],sz[a3]=sz[a2],head[a2]=sz[a2]=0;
46                 }
47                 ans-=comb[a2]; ans-=comb[a3]; comb[a2]=comb[a3]=0;
48                 for(int i=head[a3];i;i=next[i])if(i==head[a3]||i!=last[i]-1)comb[a3]++;
49                 ans+=comb[a3];
50             }
51         }
52     }
53     return 0;
54 }

20160320

时间: 2024-11-03 22:38:19

bzoj1483的相关文章

BZOJ1483: [HNOI2009]梦幻布丁

1483: [HNOI2009]梦幻布丁 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1076  Solved: 452[Submit][Status] Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. Input 第一行给出N,M表示布丁的个数和好友的操作次数. 第二行N个数A1,A2...An表示第i个布丁的

【BZOJ1483】[HNOI2009]梦幻布丁 链表+启发式合并

[BZOJ1483][HNOI2009]梦幻布丁 Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. Input 第一行给出N,M表示布丁的个数和好友的操作次数. 第二行N个数A1,A2...An表示第i个布丁的颜色从第三行起有M行,对于每个操作,若第一个数字是1表示要对颜色进行改变,其后的两个整数X,Y表示将所有颜色为X的变为Y,X可能等于Y. 若第一个数字为2

【BZOJ1483】【链表启发式合并】梦幻布丁

Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. Input 第一行给出N,M表示布丁的个数和好友的操作次数. 第二行N个数A1,A2...An表示第i个布丁的颜色从第三行起有M行,对于每个操作,若第一个数字是1表示要对颜色进行改变,其后的两个整数X,Y表示将所有颜色为X的变为Y,X可能等于Y. 若第一个数字为2表示要进行询问当前有多少段颜色,这时你应该输出一个

【BZOJ1483】【HNOI2009】梦幻布丁

题意:n个连续的点,有若干种颜色,每个颜色会因为某些操作变为另一种颜色,动态查询颜色段数. 解题思路:对每个颜色开一棵平衡树启发式合并应该是最裸的想法,但是我们有更优的! 考虑对每个颜色利用链表储存它的集合,在合并两种颜色时可以很简单通过对比原节点位置的前后颜色来进行答案的更新,然后利用启发式合并进行保证合并效率即可. 总复杂度: \( O( q \log c ) \) / \( O (c) \) C表示颜色数.(目前是BZOJ Rank2 200ms) #include <stdio.h>

bzoj1483: [HNOI2009]梦幻布丁(链表+启发式合并)

题目大意:一个序列,两种操作. ①把其中的一种数修改成另一种数 ②询问有多少段不同的数如1 2 2 1为3段(1 / 2 2 / 1). 昨晚的BC的C题和这题很类似,于是现学现写居然过了十分开心. 先把初始序列的答案统计出来,然后把每种数都用一个链表串起来,修改的时候把两种数的链表合并一下.修改答案的时候,比如把数x全部修改为数y,那么把数x的链表遍历一次,某个数x左边有y就把答案-1,右边有y也-1. 接下来是重点了:要把链表长度小的接在链表长度大的后面,才能做到nlogn.因为把链表长度小

【链表+启发式合并】Bzoj1483 [HNOI2009] 梦幻布丁

Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. Input 第一行给出N,M表示布丁的个数和好友的操作次数. 第二行N个数A1,A2...An表示第i个布丁的颜色从第三行起有M行,对于每个操作,若第一个数字是1表示要对颜色进行改变,其后的两个整数X,Y表示将所有颜色为X的变为Y,X可能等于Y. 若第一个数字为2表示要进行询问当前有多少段颜色,这时你应该输出一个

【搭楼】做题记录

以后做了题还是在这里写一下,觉得好的再去发题解(感觉无脑发题解意义不大) 也不一定是做了的题,看了没打但觉得不错的也可以发上来 (5.23-5.24 第三次月考被X得相当爽) 5.23 星期六 [贪心]Bzoj4027 HEOI2014 兔子与樱花 要是父亲合并儿子又合并就混乱了.然后发现,反正贡献都是一?能合并就在儿子处合并?贪心. [分块]Bzoj3343 教主的魔法 做之前知道了tag,于是很快就想到了算法.还没打过分块呢,于是先去膜拜了一下别人的代码.自己打出来后各种WA,太晚了没调出来

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734

Bzoj20题计划

给自己一个期限>'_'<:from 5.25~暑假前 本来已经34题了的说,现在开始继续刷50题的话可能我这辈子都写不完QAQ 知道解法的先打一下解法,希望dalao如果觉得解法菜跟我说一下>_< 目前以涉及:splay,线段树,树状数组,分块,莫队,网络流,各种dp [bzoj1067]降雨量:线段树搞事情 [bzoj1036]树的统计:树剖裸题 [bzoj1001]狼抓兔子:最小割 [bzoj2761]不重复数字:hash(map为什么会re!!!) [bzoj1588]营业额