• 「CF301D Yaroslav and Divisors」


    题目大意

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

    分析

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

    时间复杂度 (mathcal{O}(nlog^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;
    }
    
  • 相关阅读:
    python学习笔记3:python读写文件
    python学习笔记3:字典
    python学习笔记3:列表、元组和集合
    python学习笔记2:字符串
    Linux之DNS
    网络安全
    linux之防火墙
    Linux之进程管理命令
    Linux之进程管理基础
    Linux之网络
  • 原文地址:https://www.cnblogs.com/Sxy_Limit/p/14070670.html
Copyright © 2020-2023  润新知