codeforces 474F F. Ant colony(線段樹+數論)
阿新 • • 發佈:2019-01-25
題目連結:
題目大意:
給出一些數,每次給出一個區間,所有的數兩兩比較,如果a能整除b得一分,b能整除a得一分,問沒有得滿分的有多少個。
題目分析:
- 我們可以知道,每個區間的數最多隻有一種數字滿足條件,也就是所有數的gcd,那麼我們利用線段樹,維護某一個區間的gcd,和這個gcd出現的次數即可,無修改的線段樹水題
AC程式碼:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAX 100007
using namespace std;
typedef pair<int,int> PII;
int n,m;
int a[MAX];
struct Tree
{
int l,r,gcd,num;
}tree[MAX<<2];
int gcd ( int a , int b )
{
return !b?a:gcd(b,a%b);
}
void push_up ( int u )
{
int a = tree[u<<1].gcd;
int b = tree[u<<1|1].gcd;
int x = tree[u<<1 ].num;
int y = tree[u<<1|1].num;
int d = gcd ( a , b );
tree[u].gcd = d;
tree[u].num = 0;
if ( d == a )
tree[u].num += x;
if ( d == b )
tree[u].num += y;
}
void build ( int u , int l , int r )
{
tree[u].l = l;
tree[u].r = r;
if ( l == r )
{
tree[u].gcd = a[l];
tree[u].num = 1 ;
return;
}
int mid = l+r>>1;
build ( u<<1 , l , mid );
build ( u<<1|1 , mid+1 , r );
push_up ( u );
}
PII query ( int u , int left , int right )
{
int l = tree[u].l;
int r = tree[u].r;
if ( left <= l && r <= right )
return make_pair ( tree[u].gcd , tree[u].num );
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 ( )
{
while ( ~scanf ( "%d" , &n ) )
{
for ( int i = 1 ; i <= n ; i++ )
scanf ( "%d" , &a[i] );
build ( 1 , 1 , n );
scanf ( "%d" , &m );
while ( m-- )
{
int l,r;
scanf ( "%d%d" , &l , &r );
printf ( "%d\n" , r-l+1-query ( 1, l , r ).second );
}
}
}