zoukankan      html  css  js  c++  java
  • UVa12345 Dynamic len(set(a[L:R])) <带修莫队>

    Dynamic len(set(a[L:R]))

    In python, we can use len(start(a[L:R])) to calculate the number of distinct values of elements a[L],
    a[L + 1], . . . , a[R ? 1].
    Here are some interactive examples that may help you understand how it is done. Remember that
    the indices of python lists start from 0.

    a=[1,2,1,3,2,1,4]

    print a[1:6]
    [2, 1, 3, 2, 1]
    print set(a[1:6])
    set([1, 2, 3])
    print
    len(set(a[1:6]))
    3
    a[3]=2
    print
    len(set(a[1:6]))
    2
    print len(set(a[3:5]))
    1
    Your task is to simulate this process.

    Input
    There will be only one test case. The first line contains two integers n and m (1 ≤ n; m ≤ 50; 000).
    The next line contains the original list.
    All the integers are between 1 and 1,000,000 (inclusive). The next m lines contain the statements
    that you need to execute.
    A line formatted as ‘M x y’ (1 ≤ y ≤ 1; 000; 000) means a[x] = y", and a line formatted as ‘Q x
    y’ means print len(set(a[x : y]))".
    It is guaranteed that the statements will not cause index out of range" error.
    Output
    Print the simulated result, one line for each query.

    Sample Input
    7 4
    1 2 1 3 2 1 4
    Q 1 6
    M 3 2
    Q 1 6
    Q 3 5
    Sample Output
    3
    2
    1

    标签:带修莫队

    题目大意:给出一个长为n的序列,有m个操作,分为两类:1. $Q a b$ 询问此序列a~b位间有多少种不同数;2. $M a b$ 将第a位改为b。

    本题数据范围只有五万,一看就是带根号的算法,可以$O(nsqrt{n})$莫队水过。
    我们发现Q操作是标准莫队,但M操作是修改,因而需用带修莫队。
    带修莫队即在普通莫队的双指针种再加一个指针,指向时间。对于离线后询问建的扩展,如果是同一时间,就直接移动双指针;如果是不同时间,就先暴力移动时间指针,然后再移双指针即可。
    暴力出奇迹~~~

    附上AC代码:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #define MAX_N 50000
    #define MAX_C 1000000
    using namespace std;
    int n, m, tmp, col[MAX_N+5];
    int cnt[MAX_C+5], pos[MAX_N+5], lst[MAX_N+5], ans[MAX_N+5];
    bool mark[MAX_N+5];
    struct Modify {int pos, x, pre;} M[MAX_N+5];
    struct Query {int l, r, id, ts;} Q[MAX_N+5];
    bool cmp(const Query &a, const Query &b) {
    	return	pos[a.l] < pos[b.l] || 
    			(pos[a.l] == pos[b.l] && pos[a.r] < pos[b.r]) || 
    			(pos[a.l] == pos[b.l] && pos[a.r] == pos[b.r] && a.ts < b.ts);
    }
    void add(int x) {
    	if (mark[x]) {
    		cnt[col[x]]--;
    		if (!cnt[col[x]])	tmp--;
    	} else {
    		if (!cnt[col[x]])	tmp++;
    		cnt[col[x]]++;
    	}
    	mark[x] ^= 1;
    }
    void change(int x, int y) {
    	if (mark[x])	add(x), col[x] = y, add(x);
    	else	col[x] = y;
    }
    int main() {
    	scanf("%d%d", &n, &m);
    	int magic = (int)(sqrt((double)n+0.5));
    	int tot = 0, ind = 0;
    	for (int i = 1; i <= n; i++)	scanf("%d", &col[i]), lst[i] = col[i], pos[i] = i/magic;
    	for (int i = 1; i <= m; i++) {
    		char opt[2];
    		int x, y;
    		scanf("%s%d%d", opt, &x, &y);	x++;
    		if (opt[0] == 'Q') {
    			Q[++tot].id = tot;
    			Q[tot].l = x, Q[tot].r = y, Q[tot].ts = ind;
    		} else {
    			M[++ind].pos = x, M[ind].x = y, M[ind].pre = lst[x];
    			lst[x] = y;
    		}
    	}
    	sort(Q+1, Q+tot+1, cmp);
    	int now = 0, l = 1, r = 0;
    	for (int i = 1; i <= tot; i++) {
    		if (now < Q[i].ts)	for (int j = now+1; j <= Q[i].ts; j++)	change(M[j].pos, M[j].x);
    		if (now > Q[i].ts)	for (int j = now; j > Q[i].ts; j--)	change(M[j].pos, M[j].pre);
    		if (l > Q[i].l)	for (int j = l-1; j >= Q[i].l; j--)	add(j);
    		if (r < Q[i].r)	for (int j = r+1; j <= Q[i].r; j++)	add(j);
    		if (l < Q[i].l)	for (int j = l; j < Q[i].l; j++)	add(j);
    		if (r > Q[i].r)	for (int j = r; j > Q[i].r; j--)	add(j);
    		now = Q[i].ts, l = Q[i].l, r = Q[i].r;
    		ans[Q[i].id] = tmp;
    	}
    	for (int i = 1; i <= tot; i++)	printf("%d
    ", ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    并查集
    结构体字节对齐
    Dijkstra算法(单源最短路径)
    图的遍历
    二叉树的非递归遍历
    浅谈C语言中的联合体
    二叉排序(查找)树
    KMP算法
    C语言文件操作解析(四)
    Trie树
  • 原文地址:https://www.cnblogs.com/AzraelDeath/p/7592770.html
Copyright © 2011-2022 走看看