zoukankan      html  css  js  c++  java
  • 数颜色[国家集训队2011]

    【题目描述】

    墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令:

    • 1.Q L R代表询问你从第(L)支画笔到第(R)支画笔中共有几种不同颜色的画笔。

    • 2.R P Col 把第(P)支画笔替换为颜色(Col)。为了满足墨墨的要求,你知道你需要干什么了吗?

    【输入格式】

    (1)行两个整数(N,M),分别代表初始画笔的数量以及墨墨会做的事情的个数。

    (2)(N)个整数,分别代表初始画笔排中第(i)支画笔的颜色。

    (3)行到第(2+M)行,每行分别代表墨墨会做的一件事情,格式见题干部分。

    【输出格式】

    对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第(L)支画笔到第(R)支画笔中共有几种不同颜色的画笔。

    题解

    来补一道带修莫队的模板题

    什么情况下用带修莫队?

    当询问是询问一段区间,并且修改操作可以(O(1))进行并更新答案时

    带修莫队相当于是在基本莫队上加了个时间维度(t),表示这次询问之前一共有(t)次修改。

    在转移询问区间的时候,(t)也一样从上一个询问的(t)向下一个询问的(t)进行/撤回修改。

    带修莫队的块大小就不是取(sqrt{n})了,而是取(n^{frac{2}{3}}),也就是(sqrt[3]{n^2})

    我们把每个询问表示成这种形式({l,r,t}),其中(l,r)是询问区间,(t)表示这次询问之前一共有(t)次修改。

    然后按照先比(l)再比(r)最后比(t)的顺序来进行排序(当然是比较所在的块)

    然后暴力转移修改 可以证明这样做的时间复杂度约为(O(n^{frac{5}{3}})),跑(50000sim 100000)应该问题不大

    (l,r)的修改就和普通莫队一样,(t)的修改则有些不同:

    如果某次要进行/撤销的修改操作对当前区间([l,r])有影响,就需要更新答案,否则只需要改动原数组的元素

    总之也很容易写就是了

    这题具体怎么写就不用多说了吧。。。

    吐槽一下 洛谷上面这题太卡常了 2s时限卡了半天勉强过了

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') f = -1;
    	for (; ch <= '9' && ch >= '0'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ '0');
    	return x * f;
    }
    
    inline void write(int x) {
    	if (x > 9) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    int n, m, a[140005], b[140005], sz, tot, tme, nowans, ans[140005], cnt[1000005];
    int nowl, nowr, nowt;
    char s[5];
    
    struct query{
    	int l, r, t, id;
    	friend bool operator < (query x, query y) {
    		if (x.l / sz == y.l / sz) {
    			if (x.r / sz == y.r / sz) return x.t < y.t;
    			else return x.r / sz < y.r / sz;
    		} else return x.l / sz < y.l / sz;
    	}
    } q[140005];
    
    struct modify{
    	int p, x, y;
    } q2[140005];
    
    inline void upd(int x, int v) {
    	cnt[x] += v;
    	if (cnt[x] == 0 && v == -1) nowans--;
    	if (cnt[x] == 1 && v == 1) nowans++;
    }
    
    inline void updtime(int t, int v) {
    	if (v == 1) {
    		if (nowl <= q2[t].p && q2[t].p <= nowr) {
    			upd(q2[t].x, -1); upd(q2[t].y, 1);
    		}
    		a[q2[t].p] = q2[t].y;
    	} else {
    		if (nowl <= q2[t].p && q2[t].p <= nowr) {
    			upd(q2[t].y, -1); upd(q2[t].x, 1); 
    		}
    		a[q2[t].p] = q2[t].x;
    	}
    }
    
    int main() {
    	n = read(), m = read();
    	sz = pow(n, 2.0 / 3);
    	for (int i = 1; i <= n; i++) {
    		a[i] = b[i] = read();
    	}
    	for (int i = 1, x, y; i <= m; i++) {
    		scanf("%s", s);
    		x = read(), y = read();
    		if (s[0] == 'Q') {
    			q[++tot] = {x, y, tme, tot};
    		} else {
    			q2[++tme] = {x, b[x], y};
    			b[x] = y;
    		}
    	}
    	sort(q + 1, q + tot + 1);
    	nowl = 1, nowr = nowt = 0;
    	for (int i = 1; i <= tot; i++) {
    		while (nowt < q[i].t) updtime(++nowt, 1);
    		while (nowt > q[i].t) updtime(nowt--, -1);
    		while (nowl < q[i].l) upd(a[nowl++], -1);
    		while (nowl > q[i].l) upd(a[--nowl], 1);
    		while (nowr < q[i].r) upd(a[++nowr], 1);
    		while (nowr > q[i].r) upd(a[nowr--], -1);
    		ans[q[i].id] = nowans;
    	}
    	for (int i = 1; i <= tot; i++) {
    		write(ans[i]);
    		puts("");
    	}
    	return 0;
    } 
    
  • 相关阅读:
    linq语法2 GLenn
    sql 拼接字符串 GLenn
    每日算法 20130225 GLenn
    linq语法1 GLenn
    每日算法 20130227 GLenn
    每日算法 20130226 GLenn
    jquery ajax 分页 GLenn
    PhoneGap应用开发对策:如何通过苹果审核?
    Xcode 4.1/4.2/4.3/4.4/4.5 + iOS 5.1.1免证书(iDP)开发+真机调试+生成IPA全攻略
    rails 散乱记录
  • 原文地址:https://www.cnblogs.com/ak-dream/p/AK_DREAM72.html
Copyright © 2011-2022 走看看