• [HNOI2009]梦幻布丁


    洛谷题目链接

    我们对每一个颜色开一个队列,一开始的答案很显然可以(O(n))得到,那么我们每改一个地方从(x)变为(y)的话,看一看这个位置前后是不是为(y),如果是的话,初始答案(-1)

    并且,每一次修改相当于合并两个队列,那就想到启发式合并了,那么其实把(x)变成(y),把(y)变成(x)其实是一样的,只不过对后面的修改操作有影响

    那么我们用(col[i])数组表示现在是(i)这个颜色的链表原来是什么颜色

    接下来是美滋滋的代码时间~~~

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 1500007
    using namespace std;
    int n,m,ans;
    int a[N],col[N],siz[N],head[N],nxt[N];
    void Merge(int &x,int &y)
    {
    	if(siz[x]>siz[y])
    		swap(x,y);
    	if(!siz[x]||x==y)
    		return;
    	for(int i=head[x];i!=-1;i=nxt[i])
    		ans-=(a[i-1]==y)+(a[i+1]==y);
    	for(int i=head[x];i!=-1;i=nxt[i])
    	{
    		a[i]=y;
    		if(nxt[i]==-1)
    		{
    			nxt[i]=head[y];
    			head[y]=head[x];
    			break;
    		}
    	}
    	siz[y]+=siz[x];
    	siz[x]=0;
    	head[x]=0;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=N-7;++i)
    		head[i]=-1,col[i]=i;
    	for(int i=1;i<=n;++i)
    	{
    		scanf("%d",&a[i]);
    		nxt[i]=head[a[i]];
    		head[a[i]]=i;
    		++siz[a[i]];
    		if(a[i-1]!=a[i])
    			++ans;
    	}
    	for(int i=1;i<=m;++i)
    	{
    		int opt,x,y;
    		scanf("%d",&opt);
    		if(opt==2)
    			printf("%d
    ",ans);
    		else
    		{
    			scanf("%d%d",&x,&y);
    			Merge(col[x],col[y]);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    第五周读书笔记
    第五周课后作业(浅谈腾讯的创新)
    对象数组按属性排序
    id,pid数组转拓扑树结构
    ES6数组reduce()方法详解及高级技巧
    vue实现打印功能
    Js es6中扩展运算符(...)
    Axios 各种请求方式传递参数格式
    vue项目全局使用axios
    安装vue-cli脚手架
  • 原文地址:https://www.cnblogs.com/yexinqwq/p/11167085.html
Copyright © 2020-2023  润新知