• 【洛谷P4867】Gty的二逼妹子序列


    题目

    题目链接:https://www.luogu.com.cn/problem/P4867

    Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了一个难题。

    对于一段妹子们,他们想让你帮忙求出这之内美丽度(in [a,b])的妹子的美丽度的种类数。

    为了方便,我们规定妹子们的美丽度全都在([1,n])中。
    给定一个长度为(n(1 le n le 100000))的正整数序列(s(1 le si le n)),对于(m(1 le m le 1000000))次询问l,r,a,b,每次输出(s_l cdots s_r)中,权值(in [a,b])的权值的种类数。

    思路

    如果没有 (a,b) 的约束,随便搞一个莫队就可以了。
    但是有 (a,b) 的限制之后,我们统计答案的时候如果暴力枚举 ([a,b]) 的数值复杂度显然是 (O(nm)),如果用树状数组求区间和的话,莫队的端点每移动一次都会多出 (O(log n)) 的复杂度,总复杂度是 (O(n^{frac{3}{2}}log n)),不可接受。
    发现统计答案只有 (O(m)) 次,所以我们可以考虑一个修改 (O(1)),查询 (O(sqrt{n})) 的做法。值域分块一下,每次 ([a,b]) 就转换为了左右的零散区间和中间的完整区间。
    时间复杂度 (O(msqrt{n}))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=100010,M=1000010;
    int n,m,T,ans[M],a[N],cnt[N],sum[N],bel[N];
    
    struct node
    {
    	int l,r,a,b,id;
    }ask[M];
    
    bool cmp(node x,node y)
    {
    	return bel[x.l]==bel[y.l] ? x.r<y.r : bel[x.l]<bel[y.l];
    }
    
    void add(int x)
    {
    	if (!cnt[x]) sum[bel[x]]++;
    	cnt[x]++;
    }
    
    void del(int x)
    {
    	cnt[x]--;
    	if (!cnt[x]) sum[bel[x]]--;
    }
    
    int calc(int l,int r)
    {
    	int s=0;
    	for (int i=l;i<=r;i++)
    		s+=(cnt[i]>0);
    	return s;
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	T=sqrt(n)+1;
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		bel[i]=(i-1)/T+1;
    	}
    	for (int i=1;i<=m;i++)
    	{
    		scanf("%d%d%d%d",&ask[i].l,&ask[i].r,&ask[i].a,&ask[i].b);
    		ask[i].id=i;
    	}
    	sort(ask+1,ask+1+m,cmp);
    	for (int i=1,l=1,r=0;i<=m;i++)
    	{
    		for (;l>ask[i].l;l--) add(a[l-1]);
    		for (;r>ask[i].r;r--) del(a[r]);
    		for (;r<ask[i].r;r++) add(a[r+1]);
    		for (;l<ask[i].l;l++) del(a[l]);
    		int p=(ask[i].a-1)/T+1,q=(ask[i].b-1)/T+1,id=ask[i].id;
    		if (p==q) ans[id]=calc(ask[i].a,ask[i].b);
    		else
    		{
    			ans[id]=calc(ask[i].a,T*p)+calc(T*(q-1)+1,ask[i].b);
    			for (int j=p+1;j<q;j++)
    				ans[id]+=sum[j];
    		}
    	}
    	for (int i=1;i<=m;i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    Java实现交替字符串
    Java实现交替字符串
    Java实现格子取数问题
    Java实现格子取数问题
    Java实现格子取数问题
    Java实现格子取数问题
    Java实现格子取数问题
    主要C++流派,看看你是哪一流
    WPF与WinForm的抉择
    编译icu库(用到了cygwin)
  • 原文地址:https://www.cnblogs.com/stoorz/p/14025163.html
Copyright © 2020-2023  润新知