zoukankan      html  css  js  c++  java
  • Codeforces 848C (cdq分治)

    Codeforces 848C Goodbye Souvenir

    Problem :
    给一个长度为n的序列,有q个询问。一种询问是修改某个位置的数,另一种询问是询问一段区间,对于每一种值出现的最右端点的下标与最左端点的下标的差值求和。
    Solution :
    定义pre[i] 为 第i个位置的数字上一次出现位置,对于询问l, r 就是对于所有满足
    l <= pre[i] < i <= r 的点求和,权值为 i - pre[i]。
    因此可以把这个看作是三维偏序的问题,第一维时间,第二维,第三维pre[i], i,用cdq分治求解。
    对每一种值开一个set进行预处理,把每一次修改造成的影响表示成 pre[i], i, val 的形式。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e6 + 8;
    
    int n, q, tot, num;
    int a[N];
    long long ans[N];
    struct node
    {
    	int type, x, y, id;
    	bool operator < (const node &b) const
    	{
    		return x < b.x || x == b.x && type < b.type;
    	}
    	void print()
    	{
    		cout << type << " " << x << " " << y << " " << id << endl;
    	}  
    }Q[N], tmp[N];
    set <int> S[N];
    struct BIT
    {
    	long long a[N];
    	int len;
    	void init(int l)
    	{
    		len = l;
    		for (int i = 0; i < len; ++i) a[i] = 0;
    	}
    	void insert(int x, int y)
    	{
    		for (int i = x; i < len; i += i & (-i))
    			a[i] += y;
    	}
    	long long query(int x)
    	{
    		long long res = 0;
    		for (int i = x; i > 0; i -= i & (-i))
    			res += a[i];
    		return res;
    	}
    	void clear(int x)
    	{
    		for (int i = x; i < len; i += i & (-i))
    			if (a[i] != 0) a[i] = 0; else break;
    	}
    }T;
    void cdq(int l, int r)
    {
    	if (l == r) return; 
    	int mid = l + r >> 1;
    	cdq(l, mid);
    	cdq(mid + 1, r);
    	int i = l, j = mid + 1;
    	for (int k = l; k <= r; ++k)
    		if (j > r || i <= mid && Q[i] < Q[j])
    		{
    			tmp[k] = Q[i++];
    			if (tmp[k].type == 1)
    			{
    				T.insert(n - tmp[k].y + 1, tmp[k].id);
    			}
    		}
    		else
    		{
    			tmp[k] = Q[j++];
    			if (tmp[k].type == 2)
    			{
    				ans[tmp[k].id] += T.query(n - tmp[k].y + 1);
    			}
    		}
    	for (int k = l; k <= r; ++k) 
    	{
    		Q[k] = tmp[k];
    		T.clear(n - tmp[k].y + 1);
    	}
    }
    void update(int pos, int y)
    {
    	if (a[pos] == y) return;
    	auto it = S[a[pos]].find(pos);
    	auto it1 = it; it1--;
    	auto it2 = it; it2++;
    	Q[++tot] = (node){1, *it, *it1, *it1 - *it};
    	Q[++tot] = (node){1, *it2, *it, *it - *it2};
    	Q[++tot] = (node){1, *it2, *it1, *it2 - *it1};
    	S[a[pos]].erase(pos);
    	
    	a[pos] = y; S[a[pos]].insert(pos);
    	
    	it = S[a[pos]].find(pos);
    	it1 = it; it1--;
    	it2 = it; it2++;
    	Q[++tot] = (node){1, *it, *it1, *it - *it1};
    	Q[++tot] = (node){1, *it2, *it, *it2 - *it};
    	Q[++tot] = (node){1, *it2, *it1, *it1 - *it2};
    }
    void init()
    {
    	cin >> n >> q;
    	tot = 0;
    	for (int i = 1; i <= n; ++i) S[i].insert(0), S[i].insert(n + 1);
    	for (int i = 1; i <= n; ++i)
    	{
    		int x; cin >> x; a[i] = x;
    		S[x].insert(i);
    		auto it = S[x].find(i);
    		it--;
    		Q[++tot] = (node){1, i, *it, i - (*it)};
    	}
    	num = 0;
    	for (int i = 1; i <= q; ++i)
    	{
    		int type, x, y;
    		cin >> type >> x >> y;
    		if (type == 2)
    		{
    			Q[++tot] = (node){2, y, x, ++num};
    		}
    		else
    		{
    			update(x, y);
    		}
    	}
    }
    void solve()
    {
    	T.init(n + 10);
    	cdq(1, tot);
    	
    	for (int i = 1; i <= num; ++i)
    		cout << ans[i] << endl;
    }
    int main()
    {
    	cin.sync_with_stdio(0);
    	init();
    	solve();
    }
    
  • 相关阅读:
    基础总结深入:数据类型的分类和判断(数据、内存、变量) 对象 函数 回调函数 IIFE 函数中的this 分号
    BOM 定时器 通过修改元素的类来改变css JSON
    事件 事件的冒泡 事件的委派 事件的绑定 事件的传播
    DOM修改 使用DOM操作CSS
    包装类 Date Math 字符串的相关的方法 正则表达式 DOM DOM查询
    数组 call()、apply()、bind()的使用 this arguments
    autocad 二次开发 最小包围圆算法
    win10 objectarx向导在 vs2015中不起作用的解决办法
    AutoCad 二次开发 jig操作之标注跟随线移动
    AutoCad 二次开发 文字镜像
  • 原文地址:https://www.cnblogs.com/rpSebastian/p/7523085.html
Copyright © 2011-2022 走看看