zoukankan      html  css  js  c++  java
  • SPOJ DQUERY 离线树状数组+离散化

    LINK

    题意:给出$(n <= 30000)$个数,$q <= 2e5$个查询,每个查询要求给出$[l,r]$内不同元素的个数

    思路:这题可用主席树查询历史版本的方法做,感觉这个比较容易想到...但是主席树不太会用 其次可以用莫队分块的方法暴力过,再来就是使用树状数组维护不同数量的前缀和了,如果不使用离散化直接用map的话还会TLE... 通过维护当前位置上的数所记录的下标最靠右(即最近一次出现的位置),一边维护数量的前缀和,一边检查是否到达某个查询的右边界,再通过前缀性质减一下就得出了。

    /** @Date    : 2017-05-08 22:59:06
      * @FileName: SPOJ DQUERY BIT or 主席树 or 莫队.cpp
      * @Platform: Windows
      * @Version : $Id$
      */
    #include <bits/stdc++.h>
    #define LL long long
    #define PII pair
    #define MP(x, y) make_pair((x),(y))
    #define fi first
    #define se second
    #define PB(x) push_back((x))
    #define MMG(x) memset((x), -1,sizeof(x))
    #define MMF(x) memset((x),0,sizeof(x))
    #define MMI(x) memset((x), INF, sizeof(x))
    using namespace std;
    
    const int INF = 0x3f3f3f3f;
    const int N = 1e5+20;
    const double eps = 1e-8;
    
    vector v;
    int a[30100];
    int C[30100];
    int pos[30100];
    struct  yuu
    {
    	int l, r, m;
    	bool operator <(const yuu &a) const
    	{
    		return this->r < a.r;
    	}
    }b[2*N];
    int ans[2*N];
    int n, q;
    int cmp(yuu a, yuu b)
    {
    	return a.r < b.r;
    }
    
    void add(int x, int v)
    {
    	while(x <= n)
    	{
    		C[x] += v;
    		x += (-x) & x;
    	}
    	return ;
    }
    
    int getsum(int x)
    {
    	int res = 0;
    	while(x)
    	{
    		res += C[x];
    		x -= (-x) & x;
    	}
    	return res;
    }
    
    int main()
    {
    	while(~scanf("%d", &n))
    	{
    		for(int i = 1; i <= n; i++)
    		{
    			scanf("%d", a + i);
    			v.PB(a[i]);
    		}
    		scanf("%d", &q);
    		for(int i = 0; i < q; i++)
    		{
    			scanf("%d%d", &b[i].l, &b[i].r);
    			b[i].m = i;
    		}
    		sort(v.begin(), v.end());
    		v.erase(unique(v.begin(),v.end()), v.end());
    		for(int i = 1; i <= n; i++)
    		{
    			a[i] = lower_bound(v.begin(),v.end(), a[i]) - v.begin();
    		}
    		sort(b, b + q);
    		MMF(C);
    		MMF(pos);
    		int cnt = 0;
    		for(int i = 1; i <= n; i++)
    		{
    			if(!pos[a[i]])
    			{
    				add(i, 1);
    				pos[a[i]] = i;
    			}
    			else
    			{
    				add(i, 1);
    				add(pos[a[i]], -1);
    				pos[a[i]] = i;
    			}
    			while(cnt < q && i == b[cnt].r)
    			{
    				ans[b[cnt].m] = getsum(b[cnt].r) - getsum(b[cnt].l - 1);
    				cnt++;
    			}
    		}
    		for(int i = 0; i < q; i++)
    			printf("%d
    ", ans[i]);
    	}
        return 0;
    }
    
  • 相关阅读:
    uva 10129 poj 1386 hdu 1116 zoj 2016 play on words
    redis持久化
    Redis事务
    非阻塞I/O多路复用机制
    SFTP
    FTP
    http协议特点及session共享及单点登录
    什么是cookie以及cookie的特性、优缺点
    异步IO和同步IO的区别:
    TCP操作与原理
  • 原文地址:https://www.cnblogs.com/Yumesenya/p/6832757.html
Copyright © 2011-2022 走看看