• [HNOI2009]梦幻布丁


    Problem

    题目传送门

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

    (n , m< 10^5, a_i, x, y <10^6)

    solution

    一种颜色的布丁变成另一种颜色就相当于合并两种颜色的布丁。

    并且两种布丁合并了之后显然不可能分开。

    所以考虑启发式合并。

    对于每种颜色,开一个vector记录当前颜色在哪些位置出现。

    合并时小向大合并,计算答案即可。

    然后愉快的咕了……

    原因是:有时候我们需要将颜色x变成y,而此时siz[x]>siz[y]……直接合并的话显然是有问题的。

    所以,我们需要用一个数组记录下每个颜色的真实颜色。

    如果siz[x]>siz[y]但需要将颜色x变成y时,我们可以先将y变成x,计算答案之后,再将颜色x的真实颜色改为y即可。

    这样复杂度和答案的正确性都有保证。

    (撒花)^_^

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
    #define mp make_pair
    #define fst first
    #define snd second
    
    template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
    template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
    
    inline int read(){
    	int res = 0, fl = 1;
    	char r = getchar();
    	for (; !isdigit(r); r = getchar()) if(r == '-') fl = -1;
    	for (; isdigit(r); r = getchar()) res = (res << 3) + (res << 1) + r - 48;
    	return res * fl;
    }
    typedef long long LL;
    typedef pair<int, int> pii;
    const int Maxn = 1e6 + 10;
    vector<int> plc[Maxn];
    int b[Maxn], col[Maxn], a[Maxn], n, m, ans;
    struct ASK{
    	int opt, x, y;
    }ask[Maxn];
    void merge(int x,int y){
    	for (int i = plc[x].size() - 1; i >= 0; --i)
    		ans -= (a[plc[x][i] - 1] == y) + (a[plc[x][i] + 1] == y);
    	for (int i = plc[x].size() - 1; i >= 0; --i) a[plc[x][i]] = y, plc[y].push_back(plc[x][i]);
    	plc[x].clear();
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("a.in", "r", stdin);
    	freopen("a.out", "w", stdout);
    #endif
    	int n = read(), m = read();
    	for (int i = 1; i <= n; ++i) a[i] = read(), col[a[i]] = a[i];
    	for (int i = 1; i <= n; ++i) {
    		plc[a[i]].push_back(i);
    		if(a[i] != a[i - 1]) ans++;
    	}
    	while(m--){
    		int opt = read();
    		if(opt == 2) printf("%d
    ",ans);
    		else {
    			int x = read(), y = read();
    			if(x == y) continue;
    			if(plc[col[x]].size() > plc[col[y]].size()) swap(col[x], col[y]);
    			if(plc[col[x]].size()) merge(col[x], col[y]);
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    marquee基本语法和marquee的相关参数设置
    [转]FreeTextBox使用详解
    div+css三级下拉菜单无限制下拉
    让Flash在Firefox和IE下背景透明
    asp.net制作幻灯片
    图片连续滚动代码,左右连续,上下连续不间断滚动
    纯DIV+CSS下拉菜单
    连续滚动图片代码
    sql语句修改access中的字段类型,access数据类型大全!
    非常棒的图片连续滚动代码
  • 原文地址:https://www.cnblogs.com/LZYcaiji/p/10397846.html
Copyright © 2020-2023  润新知