bzoj1483

一道挺有意思的题目

我们先预处理出答案,对每种颜色都用一个链表进行维护,操作1就是将两个链表进行合并,并维护答案,合并时应将size较小的合并至较大的(这样可以保证log n的复杂度,因为每次合并至少会使size较小的变为原来的两倍,但是有个问题,我们必须搞一个数组p[i]来表示我们查询颜色i时应该查找的真正颜色),然后就没了。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<ctime>
 5 #include<cmath>
 6 #include<iostream>
 7 #include<algorithm>
 8 #include<queue>
 9 #include<stack>
10 #include<set>
11 #define clr(a,x) memset(a,x,sizeof(a))
12 #define rep(i,l,r) for(int i=(l);i<(r);i++)
13 using namespace std;
14 typedef long long ll;
15 typedef pair<int,int> pii;
16 #define mkp(a,b) make_pair(a,b)
17 int read(){
18     int ans=0,f=1;
19     char c=getchar();
20     while(!isdigit(c)){
21         if(c=='-') f=-1;
22         c=getchar();
23     }
24     while(isdigit(c)){
25         ans=ans*10+c-'0';
26         c=getchar();
27     }
28     return ans*f;
29 }
30 const int maxn=100009,maxk=1000009;
31 int ans,n,m,a[maxn],p[maxk],s[maxk],fir[maxk],last[maxk],next[maxn];
32 void modify(int&x,int&y){
33     if(s[x]<s[y]) swap(x,y);
34     if(!s[y]) return;
35     for(int i=fir[y];i;i=next[i]){
36         if(a[i-1]==x) ans--;
37         if(a[i+1]==x) ans--;
38     }
39     for(int i=fir[y];i;i=next[i]) a[i]=x;
40     s[x]+=s[y];s[y]=0;    
41     next[last[x]]=fir[y];last[x]=last[y];fir[y]=last[y]=0;
42 }
43 int main(){
44     rep(i,1,maxk+1) p[i]=i;
45     n=read();m=read();
46     rep(i,1,n+1){
47         a[i]=read();
48         if(a[i]!=a[i-1]) ans++;
49         if(!last[a[i]]) last[a[i]]=i;
50         next[i]=fir[a[i]];
51         fir[a[i]]=i;s[a[i]]++;
52     }
53     while(m--){
54         int opt=read();
55         if(opt==1){
56             int x=read(),y=read();
57             if(x!=y) modify(p[y],p[x]);
58         }else printf("%d\n",ans);
59     }
60     return 0;
61 }
View Code

1483: [HNOI2009]梦幻布丁

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 1689  Solved: 715
[Submit][Status][Discuss]

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表示要进行询问当前有多少段颜色,这时你应该输出一个整数. 0

Output

针对第二类操作即询问,依次输出当前有多少段颜色.

Sample Input

4 3
1 2 2 1
2
1 2 1
2

Sample Output

3
1

HINT

 

Source

 
[Submit][Status][Discuss]
posted @ 2015-12-01 14:40  ChenThree  阅读(178)  评论(0编辑  收藏  举报