題目鏈接:https://codeforc.es/problemset/problem/474/F
題目大意:給定一個長度爲的序列,次詢問區間內不能活下來的數量,規則爲:區間內任意兩個數比較,若一個數能整除另一個數,則這個數的積分+1,所有數比完之後,若當前數積分,則這個數能活下來。
思路:若這個區間內存在這樣的數,那麼這樣的數肯定是區間最小的,且是區間其他數的因數,那麼我們可以用線段樹維護每次查詢的區間,若某兩個小區間能夠合併,那麼一定滿足:小區間的最小數是其他數的倍數,並且此時要更新這個區間內最小數的數量。
AC代碼:
#include<bits/stdc++.h>
using namespace std;
#define Mid ((l+r)>>1)
#define lson rt<<1,l,Mid
#define rson rt<<1|1,Mid+1,r
const int maxn=1e5+10;
int b[maxn];
struct node
{
int l,r,cnt,gcd;
}a[maxn<<2];
int gcd(int x,int y){
return y==0?x:gcd(y,x%y);
}
void push_up(int rt){
int t=gcd(a[rt<<1].gcd,a[rt<<1|1].gcd);
a[rt].gcd=t;
a[rt].cnt=0;
if(t==a[rt<<1].gcd){
a[rt].cnt+=a[rt<<1].cnt;
}
if(t==a[rt<<1|1].gcd){
a[rt].cnt+=a[rt<<1|1].cnt;
}
}
void build(int rt,int l,int r){
a[rt].l=l;
a[rt].r=r;
if(l==r){
a[rt].gcd=b[l];
a[rt].cnt=1;
return ;
}
build(lson);
build(rson);
push_up(rt);
}
typedef pair<int,int> pii;
pii query ( int u , int left , int right )
{
int l = a[u].l;
int r = a[u].r;
if ( left <= l && r <= right )
return make_pair ( a[u].gcd , a[u].cnt );
pii ret,temp;
ret.first = -1;
int mid = l+r>>1;
if ( left <= mid && right >= l )
ret = query ( u<<1 , left , right );
if ( left <= r && right > mid )
{
temp = query ( u<<1|1 ,left , right );
if ( ret.first == -1 ) ret = temp;
else
{
int d = gcd ( ret.first , temp.first );
if ( d != ret.first ) ret.second = 0;
if ( d == temp.first ) ret.second += temp.second;
ret.first = d;
}
}
return ret;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
}
build(1,1,n);
int t;
scanf("%d",&t);
while(t--){
int l,r;
scanf("%d%d",&l,&r);
pii tmp=query(1,l,r);
int ans=r-l+1-tmp.second;
printf("%d\n",ans);
}
return 0;
}