「CF301D Yaroslav and Divisors」

题目大意

给出一个排列,每次询问一个区间中满足一个数为另一个数倍数的数对个数.

分析

首先可以发现整个排列的合法数对数为 \(\mathcal{O}(n\log n)\) 级别,所以可以想到直接去维护这些数对.一个数对由两个数组成,这就不容易处理,可以想到离线去处理.对查询的右端点排序.显然可以在右端点移动时将新加入的数的贡献加入.那么现在就变成了一个后缀查询的形式,既然是后缀,不妨将一个数对的贡献放在靠前的数中,这样在查询中只有当两个数都在这个后缀中的时候才会产生贡献.于是问题变成了单点加,区间查询,可以用树状数组轻松维护.

时间复杂度 \(\mathcal{O}(n\log^2n)\).如果您有低于这个复杂度的做法可以私信我/kel.

代码

#include<bits/stdc++.h>
#define REP(i,first,last) for(register int i=(first);i<=(last);++i)
#define DOW(i,first,last) for(register int i=(first);(last)<=i;--i)
#define LL long long
#define UI unsigned int
#define ULL unsigned long long
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLI pair<long long,int>
#define PLL pair<long long,long long>
#define MPR(a,b) make_pair(a,b)
namespace IO
//快读模板
using namespace IO;
using namespace std;
const int MAXN=2e5+5;
int n,m;
int arr[MAXN];
int id[MAXN];
vector<int>link[MAXN];
class Query
{
public:
	int left,right,id;
	inline bool operator <(const Query &a)const
	{
		return right<a.right;
	}
}q[MAXN];
int answer[MAXN];
namespace BIT//单点修改+区间查询的树状数组
{
	int tree[MAXN];
	inline int Lowbit(const int now)
	{
		return now&-now;
	}
	inline void Updata(const int place)
	{
		for(register int now=place;now<=n;now+=Lowbit(now))
		{
			++tree[now];
		}
	}
	inline int Query(const int left,const int right)
	{
		register int result=0;
		for(register int now=right;now;now-=Lowbit(now))
		{
			result+=tree[now];
		}
		for(register int now=left-1;now;now-=Lowbit(now))
		{
			result-=tree[now];
		}
		return result+right-left+1;
	}
}
int main()
{
	Read(n,m);
	REP(i,1,n)
	{
		Read(arr[i]);
		id[arr[i]]=i;
	}
	REP(i,1,n)//将数对的贡献放在靠前的数中
	{
		int top=n/arr[i];
		REP(j,2,top)
		{
			if(id[arr[i]*j]<i)
			{
				link[i].push_back(id[arr[i]*j]);
			}
			else
			{
				link[id[arr[i]*j]].push_back(i);
			}
		}
	}
	REP(i,1,m)
	{
		Read(q[i].left,q[i].right);
		q[i].id=i;
	}
	sort(q+1,q+1+m);
	int now=1;
	REP(i,1,n)
	{
		if(link[i].size())
		{
			REP(j,0,link[i].size()-1)//将新加入的数的贡献放入
			{
				BIT::Updata(link[i][j]);
			}
		}
		while(q[now].right==i)
		{
			answer[q[now].id]=BIT::Query(q[now].left,q[now].right);
			++now;
		}
	}
	REP(i,1,m)
	{
		Writeln(answer[i]);
	}
	return 0;
}
posted @ 2020-12-01 20:51  SxyLimit  阅读(69)  评论(0编辑  收藏  举报