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();
    }
    
  • 相关阅读:
    Java的内存区域划分
    Java中的浮点型进行四则运算精度丢失的问题
    单例模式的几种写法
    如何掌握一门工具及对工具的认识
    记一个命运多舛的项目总结
    几个超级好用但很少有人知道的 webstorm技巧
    如何自定义中间件,实现业务代码无侵入监控及拦截
    如何减少和处理死锁
    快照读与加锁读
    谈谈Java常用类库中的设计模式
  • 原文地址:https://www.cnblogs.com/rpSebastian/p/7523085.html
Copyright © 2011-2022 走看看