1. 程式人生 > 實用技巧 >「CF301D Yaroslav and Divisors」

「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;
}