• P1903 [国家集训队]数颜色 / 维护队列 带修改的莫队


    (color{#0066ff}{ 题目描述 })

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

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

    2、 R P Col 把第P支画笔替换为颜色Col。

    为了满足墨墨的要求,你知道你需要干什么了吗?

    (color{#0066ff}{输入格式})

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

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

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

    (color{#0066ff}{输出格式})

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

    (color{#0066ff}{输入样例})

    6 5
    1 2 3 4 5 5
    Q 1 4
    Q 2 6
    R 1 2
    Q 1 4
    Q 2 6
    

    (color{#0066ff}{输出样例})

    4
    4
    3
    4
    

    (color{#0066ff}{数据范围与提示})

    对于100%的数据,N≤50000,M≤50000,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。

    (color{#0066ff}{ 题解 })

    可以用莫队做,但是带修改

    带修改的莫队,我们以(n^{frac 2 3})为一块,这样总复杂度为(O(n^{frac 5 3})),懒得证明了qwq

    排序时以左端点的块为第一关键字,右端点的块为第二关键字,时间为第三关键字

    每次到一个问题,如果当前修改的少了,就一直修改到当前位置,如果多了则撤销

    开个数组记录当前修改的位置的上一次的颜色,便于撤销,就解决了

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    const int len = 1357;
    const int maxn = 5e4 + 10;
    int bel[maxn];
    struct node {
    	int l, r, id;
    	friend bool operator < (const node &a, const node &b) {
    		if(bel[a.l] != bel[b.l]) return bel[a.l] < bel[b.l];
    		if(bel[a.r] != bel[b.r]) return bel[a.r] < bel[b.r];
    		return a.id < b.id;
    	}
    }e[maxn], c[maxn];
    int ans[maxn], a[maxn], t[1005050], pre[maxn];
    int l = 1, r = 0, tot, now;
    int n, m, qnum, cnum;
    char getch() {
    	char ch;
    	while(!isalpha(ch = getchar()));
    	return ch;
    }
    void add(int i) {
    	if(!t[i]) tot++;
    	t[i]++;
    }
    void del(int i) {
    	t[i]--;
    	if(!t[i]) tot--;
    }
    void change_add(int id) {
    	if(l <= c[id].l && c[id].l <= r) del(a[c[id].l]), add(c[id].r);
    	pre[id] = a[c[id].l];
    	a[c[id].l] = c[id].r;
    }
    void change_del(int id) {
    	if(l <= c[id].l && c[id].l <= r) del(c[id].r), add(pre[id]);
    	a[c[id].l] = pre[id];
    }
    void work(int tme) {
    	while(now < cnum && c[now + 1].id <= tme) change_add(++now);
    	while(now && c[now].id > tme) change_del(now--);
    }
    int main() {
    	n = in(), m = in();
    	for(int i = 1; i <= n; i++) a[i] = in(), bel[i] = (i - 1) / len + 1;
    	for(int i = 1; i <= m; i++) {
    		if(getch() == 'Q') {
    			qnum++;
    			e[qnum].l = in(), e[qnum].r = in(), e[qnum].id = i;
    		}
    		else {
    			cnum++;
    			c[cnum].l = in(), c[cnum].r = in(), c[cnum].id = i;
    		}
    	}
    	std::sort(e + 1, e + qnum + 1);
    	for(int i = 1; i <= qnum; i++) {
    		work(e[i].id);
    		while(l < e[i].l) del(a[l++]);
    		while(l > e[i].l) add(a[--l]);
    		while(r > e[i].r) del(a[r--]);
    		while(r < e[i].r) add(a[++r]);
    		ans[e[i].id] = tot;
    	}
    	for(int i = 1; i <= m; i++) if(ans[i]) printf("%d
    ", ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    51nod_1445 变色DNA 最短路模板 奇妙思维
    51nod_1459 最短路 dijkstra 特调参数
    UVA_10653 公主与王子 #刘汝佳DP题刷完计划
    HOJ 13819 Height map
    51nod_1255字典序最小的子序列
    电梯设计需求调研报告
    梦断代码读后感
    求一循环数组的最大子数组的和
    求二维数组中最大子数组的和
    四则运算
  • 原文地址:https://www.cnblogs.com/olinr/p/10390061.html
Copyright © 2020-2023  润新知