您的位置:首页 > 其它

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

2014-10-09 21:24 387 查看
题意:给定一个序列,查询t个区间,询问有几个数可以整除其他的数。

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

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

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

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

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

#include<iostream>
#include<algorithm>
using namespace std;
#define INF 1000000001
#define MAXN 100010
#define MIN(a,b) a<b?a:b
#define lson 2*o,l,m
#define rson 2*o+1,m+1,r
struct Node
{
int gcd,min,cnt;
}tree[4*MAXN],ans;
int s[MAXN];
int n;
int Gcd(int a,int b){
if(!b)return a;
return Gcd(b,a%b);
}
void init_tree(int o,int l,int r){
if(l==r)
{
tree[o].min=INF;
tree[o].cnt=0;
tree[o].gcd=-1;
return;
}
int m=(l+r)>>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<pos)return;
if(l==r&&l==pos){
tree[o].cnt=1;
tree[o].min=data;
tree[o].gcd=data;
return;
}
int m=(l+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(lmin<rmin)
tree[o].cnt=tree[2*o].cnt;
else
tree[o].cnt=tree[2*o+1].cnt;
}
void query(int o,int l,int r,int i,int j)
{
if(i>r||j<l)return;
if(i<=l&&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<<r-l+1<<endl;
else
cout<<r-l+1-ans.cnt<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: