Codeforces Round #271 (Div. 2)F. Ant colony(线段树)

题意:给定一个序列,查询t个区间,询问有几个数可以整除其他的数。


一个数可以整除其他的数,那么它必定是这个数的因子之一,一个数可以整除其他数,那么它必定是这些数的公因子,加上他自己的话,他就是这些数的最大公约数,一个区间内的最大公约数肯定是这个区间的最小值,因为比他大的数肯定不能整除他。所以题目是找一个区间所包含的最大公约数的个数。

区间的最大公约数等于,两个子区间分别的最大公约数的最大公约数(好拗口= =)

区间的最小值由两个子区间的最小值决定。

区间最小值的个数由左右区间的最小值决定。

有了上面这三条,就可以用线段树来维护了。


#include
#include
using namespace std;
#define INF 1000000001
#define MAXN 100010
#define MIN(a,b) a>1;
	init_tree(lson);
	init_tree(rson);
	tree[o].gcd=1;
	tree[o].cnt=0;
	tree[o].min=INF;
}
void insert(int o,int l,int r,int pos,int data)
{
	if(l>pos||r>1;
	insert(lson,pos,data);
	insert(rson,pos,data);
	int lg=tree[2*o].gcd,rg=tree[2*o+1].gcd;
	int lmin=tree[2*o].min,rmin=tree[2*o+1].min;
	tree[o].min=MIN(lmin,rmin);
	if(lg!=-1&&rg!=-1)
	tree[o].gcd=Gcd(tree[2*o].gcd,tree[2*o+1].gcd);
	else if(lg!=-1)
		tree[o].gcd=lg;
	else if(rg!=-1)
		tree[o].gcd=rg;
	if(lmin==rmin)
		tree[o].cnt=tree[2*o].cnt+tree[2*o+1].cnt;
	else if(lminr||j=r)
	{
		if(ans.gcd==-1)ans.gcd=tree[o].gcd;
		else ans.gcd=Gcd(ans.gcd,tree[o].gcd);
		if(ans.min>tree[o].min){
			ans.min=tree[o].min;
			ans.cnt=tree[o].cnt;
		}
		else if(ans.min==tree[o].min){
			ans.cnt+=tree[o].cnt;
		}
		return ;
	}
	int m=(l+r)>>1;
	query(lson,i,j);
	query(rson,i,j);
}
int main()
{
	cin>>n;
	init_tree(1,1,n);
	for(int i=1;i<=n;i++)
	{
		cin>>s[i];
		insert(1,1,n,i,s[i]);
	}
	int t;
	cin>>t;
	while(t--)
	{
		int l,r;
		cin>>l>>r;
		ans.cnt=0;ans.gcd=-1;ans.min=INF;
		query(1,1,n,l,r);
		if(ans.min!=ans.gcd)
			cout<


你可能感兴趣的:(线段树与树状数组,codeforces)