• 【洛谷P1972】HH的项链


    题目

    题目链接:https://www.luogu.com.cn/problem/P1972
    HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。
    有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答…… 因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。

    思路

    之前写的是莫队的\(O(n\sqrt{n})\)的算法。现在数据又加强了,于是回来写了一个\(O(n\log n)\)的算法。
    考虑对于一堆\(r_i=x\)的询问\(i\),我们发现,如果一个数字在\([1,x]\)中出现了多次,那么取最大的且不超过\(x\)位置的数字显然是最优的。
    那么我们在处理一堆右端点相同的询问时,我们只要知道在\([1,x]\)中每个数字出现位置最后的位置在哪里即可。
    建立一棵树状数组,处理到\(x=i\)时,树状数组中位置\(j\)表示在区间\([1,i]\)中,位置\(j\)上的数字是否是最后出现的(所以有\(c[i]\in \{0,1\}\))。那么此时对于一个询问\([l,x]\),答案就是\(\sum^{x}_{i=l}c[i]\)。树状数组\(O(\log n)\)搞定。
    在从位置\(i\)的询问转移到位置\(i+1\)的询问时,我们将\(a[i+1]\)上一次出现的位置在树状数组中清零,在位置\(i+1\)标记为1。仍然\(O(\log n)\)
    时间复杂度\(O(n\log n)\)

    代码

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    
    const int N=1000010;
    int n,m,a[N],last[N],ans[N];
    
    struct ASK
    {
    	int l,r,id;
    }ask[N];
    
    struct BIT
    {
    	int c[N];
    	
    	int ask(int x)
    	{
    		int sum=0;
    		for (int i=x;i;i-=i&-i)
    			sum+=c[i];
    		return sum;
    	}
    	
    	void add(int x,int val)
    	{
    		if (!x) return;
    		for (int i=x;i<=n;i+=i&-i)
    			c[i]+=val;
    	}
    }bit;
    
    bool cmp(ASK x,ASK y)
    {
    	return x.r<y.r;
    }
    
    int read()
    {
    	int d=0,f=1; char ch=getchar();
    	while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
    	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
    	return d*f;
    }
    
    int main()
    {
    	n=read();
    	for (int i=1;i<=n;i++)
    		a[i]=read();
    	m=read();
    	for (int i=1;i<=m;i++)
    		ask[i].l=read(),ask[i].r=read(),ask[i].id=i;
    	sort(ask+1,ask+1+m,cmp);
    	for (int i=1;i<=m;i++)
    	{
    		for (int j=ask[i-1].r+1;j<=ask[i].r;j++)
    			bit.add(last[a[j]],-1),bit.add(j,1),last[a[j]]=j;
    		ans[ask[i].id]=bit.ask(ask[i].r)-bit.ask(ask[i].l-1);
    	}
    	for (int i=1;i<=m;i++)
    		printf("%d\n",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    leecode 91. 解码方法
    leecode 166. 分数到小数
    剑指 Offer 31. 栈的压入、弹出序列
    leecode 386. 字典序排数
    LeetCode 311 稀疏矩阵的乘法
    leecode 89. 格雷编码
    leecode 79. 单词搜索
    leecode 207. 课程表
    QT -- 解决:Error: Could not decode "*.cpp" with "UTF-8"
    VS+QT -- 没有PRO文件的问题
  • 原文地址:https://www.cnblogs.com/stoorz/p/12207743.html
Copyright © 2020-2023  润新知