Function Query(树状数组)
problem
給定一個(gè)長(zhǎng)度為 nnn 的排列 aaa。有 qqq 個(gè)詢問(wèn),每次詢問(wèn)一個(gè)區(qū)間 [l,r][l,r][l,r]。求這個(gè)區(qū)間的 kkk 值。
其中 k=∑i=lr∑j=i+1rf(ai,aj),f(x,y)k=\sum_{i=l}^r\sum_{j=i+1}^rf(a_i,a_j),f(x,y)k=∑i=lr?∑j=i+1r?f(ai?,aj?),f(x,y) 為一個(gè)遞歸函數(shù),定義如下:
- 當(dāng) x=yx=yx=y,其值為 111。
- 當(dāng) n≠yn\ne yn?=y,其值為 f(x+y+∣x?y∣,∣x?y∣)f(x+y+|x-y|,|x-y|)f(x+y+∣x?y∣,∣x?y∣)。
- 若無(wú)限循環(huán),其值為 000。
n,q≤1e5n,q\le 1e5n,q≤1e5。
solution
observation1:\text{observation1}:observation1: 首先觀察這個(gè)函數(shù),不難發(fā)現(xiàn)這個(gè)函數(shù) x,yx,yx,y 的和是不變的。
所以當(dāng)這個(gè)和為奇數(shù)的時(shí)候,一定會(huì)死循環(huán),不可能走到 x=yx=yx=y 的局面。
否則 x,yx,yx,y 一定同奇偶。
observation2:\text{observation2}:observation2: 又不難知道加減運(yùn)算過(guò)程中結(jié)果仍是 gcd\text{gcd}gcd 的倍數(shù)。所以去掉不影響答案。
因此我們可以將 x,yx,yx,y 都除以他們的 gcd\text{gcd}gcd。那么此時(shí)得到的 x,yx,yx,y 均為奇數(shù)且互質(zhì)。
接下來(lái)假設(shè) x>yx>yx>y,我們可以同時(shí)除以他們的 gcd\text{gcd}gcd。
由于 x,yx,yx,y 同為奇,故 y?2,x?yy*2,x-yy?2,x?y 都是偶數(shù)。
再假設(shè) y?2,x?yy*2,x-yy?2,x?y 有與 222 互質(zhì)的公因數(shù) k(k≠1)k(k\ne 1)k(k?=1)。
則 k∣y∧k∣x?yk\mid y\wedge k\mid x-yk∣y∧k∣x?y,所以 k∣xk\mid xk∣x,這與 (x,y)=1(x,y)=1(x,y)=1 矛盾。
所以這個(gè) gcd\text{gcd}gcd 一定為 222。
所以 f(x,y)f(x,y)f(x,y) 等價(jià)于 f(x?y2,y)f(\frac{x-y}{2},y)f(2x?y?,y)。
故其和每次都會(huì)除以 222,直到 x=y=1x=y=1x=y=1 或死循環(huán)。
這樣我們就可以求出 f(i,j)f(i,j)f(i,j) 的值為 g(i+jgcd?(i,j))g(\frac{i+j}{\gcd(i,j)})g(gcd(i,j)i+j?),其中當(dāng) x=2kx=2^kx=2k 時(shí),g(x)=kg(x)=kg(x)=k;否則 g(k)=0g(k)=0g(k)=0。
假設(shè) x,yx,yx,y 最簡(jiǎn)比為 a,ba,ba,b,即 xa=yb\frac xa=\frac ybax?=by?。
我們不妨枚舉 2i2^i2i,使得 a+b=2ia+b=2^ia+b=2i,然后枚舉 aaa,自然就知道了 bbb。還需要檢查一下 a,ba,ba,b 互質(zhì)。
再枚舉這個(gè)比例,進(jìn)而也能知道 x,yx,yx,y。
顯然這樣的 (a,b)(a,b)(a,b) 有 2i2^i2i 種,且 xa=yb=d≤n2i?1\frac xa=\frac yb=d\le \frac{n}{2^{i-1}}ax?=by?=d≤2i?1n?。
這樣合法的不同的 (x,y)(x,y)(x,y) 只有 2n2n2n 對(duì)左右。
一共也就 O(nlog?n)O(n\log n)O(nlogn) 的級(jí)別,我們完全可以將這些二元組記下來(lái),問(wèn)題就轉(zhuǎn)換成了二維偏序問(wèn)題。
就可以用樹(shù)狀數(shù)組做了。
時(shí)間復(fù)雜度 O(nlog?2n)O(n\log^2n)O(nlog2n)。
其實(shí)由二離和分塊的做法,但我不會(huì)哈哈哈
code
#include <bits/stdc++.h> using namespace std; #define maxn 200005 #define int long long int n, m; int a[maxn], p[maxn], ret[maxn], t[maxn]; vector < int > G[maxn]; vector < pair < int, int > > Q[maxn];int gcd( int x, int y ) {if( ! y ) return x;else return gcd( y, x % y ); }void add( int i, int x ) {for( ;i <= n;i += i & -i ) t[i] += x; }int ask( int i ) {int ans = 0;\for( ;i;i -= i & -i ) ans += t[i];return ans; }int F( int x, int y ) {if( x == y ) return 1;if( x < y ) swap( x, y );return F( y << 1, x - y ) + 1; }void solve() {for( int i = 1;i <= n;i ++ ) {for( int j : G[i] ) {int k = F( a[j], a[i] );add( 1, k ), add( j + 1, -k );}for( auto j : Q[i] ) ret[j.second] = ask( j.first );} }signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &a[i] ), p[a[i]] = i;for( int i = 0;(1 << i) <= (n << 1);i ++ ) {for( int j = 1;j <= n;j ++ ) {int k = (1 << i) - a[j];if( k <= 0 or k > n or p[k] > j or a[j] == k ) continue;if( gcd( k, a[j] ) ^ 1 ) continue;for( int o = 1;p[o * k] and p[o * a[j]];o ++ ) {int x = p[o * k], y = p[o * a[j]];if( x > y ) swap( x, y );G[y].push_back( x );}}}scanf( "%lld", &m );for( int i = 1, l, r;i <= m;i ++ ) {scanf( "%lld %lld", &l, &r );Q[r].push_back( make_pair( l, i ) );}solve();for( int i = 1;i <= m;i ++ ) printf( "%lld\n", ret[i] );return 0; }總結(jié)
以上是生活随笔為你收集整理的Function Query(树状数组)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: qq财付通手机端给qq充Q币Q点的方法
- 下一篇: [HNOI2016] 序列(线段树 +