1. 程式人生 > >codeforces 474F F. Ant colony(線段樹+數論)

codeforces 474F F. Ant colony(線段樹+數論)

題目連結:

題目大意:

給出一些數,每次給出一個區間,所有的數兩兩比較,如果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 ); } } }