http://www.lydsy.com/JudgeOnline/problem.php?id=1483
题意:
思路:
每次修改的话需要把同一种颜色的都修改了,那如果去遍历的话就复杂度比较高,如果用链表把颜色相同的连接起来的话那么修改起来就十分方便了。
但是当两个链表需要合并的时候,修改长度短的那一个相对来说会比较省时,这就是启发式合并。但是使用启发式合并的话需要注意,如果现在有操作1->2,本来是要将所有的1改成2,如果1的链表长度大于2的链表长度的话,启发式合并就会将2合并至1,此时也就变成了将2变成1,所以我们需要一个数组pos来记录所要找的颜色在链表中实际对应的颜色。
那么当修改颜色时怎么动态维护答案呢,我们只需要扫描一遍链表,如果此时是x->y,如果颜色为x的某个数左边为y,那么ans--,右边为y,那么ans--。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 #include<cmath> 9 #include<map> 10 #include<set> 11 using namespace std; 12 typedef long long ll; 13 typedef pair<int,int> pll; 14 const int INF = 0x3f3f3f3f; 15 const int maxn = 1000000+5; 16 17 int n, m; 18 int a[maxn],sz[maxn],nxt[maxn],frt[maxn],pos[maxn]; 19 20 int main() 21 { 22 //freopen("in.txt","r",stdin); 23 scanf("%d%d",&n,&m); 24 int ans = 0; 25 for(int i=1;i<=n;i++) 26 { 27 scanf("%d",&a[i]); 28 if(a[i]!=a[i-1]) ans++; 29 sz[a[i]]++; 30 pos[a[i]]=a[i]; 31 nxt[i]=frt[a[i]],frt[a[i]]=i; 32 } 33 while(m--) 34 { 35 int op; 36 scanf("%d",&op); 37 if(op==1) 38 { 39 int x,y,num; 40 scanf("%d%d",&x,&y); 41 if(x==y) continue; 42 if(sz[pos[x]]>sz[pos[y]]) swap(pos[x],pos[y]); 43 x=pos[x],y=pos[y]; 44 if(!sz[x]) continue; 45 for(int i=frt[x];i;i=nxt[i]) 46 { 47 if(a[i+1]==y) ans--; 48 if(a[i-1]==y) ans--; 49 num = i; 50 } 51 for(int i=frt[x];i;i=nxt[i]) a[i]=y; 52 sz[y]+=sz[x],sz[x]=0; 53 nxt[num]=frt[y]; 54 frt[y] = frt[x]; 55 frt[x] = 0; 56 } 57 else printf("%d\n",ans); 58 } 59 return 0; 60 }