牛客14269 sum 線段樹 數字

2021-10-17 05:24:05 字數 2150 閱讀 4617

考慮維護乙個這樣的問題:

(1) 給出乙個陣列a,標號為1~n

(2) 修改陣列中的乙個位置。

(3) 詢問區間[l,r]中所有子集的位運算and之和mod(109+7)。

位運算and即為「pascal中的and」和「c/c++中的&」

我們定義集合s=

若集合t,t ∩ s = t,則稱t為s的子集

設f(t)=at1 and at2 and … and atk (設k為t集大小,若k=0則f(t)=0)

所有子集的位運算and之和即為∑f(t)

那麼,現在問題來了。

題解:要維護的資料結構包括區間查詢,單點修改,可以考慮用線段樹。那麼如何維護線段樹呢?關鍵在於如何處理子集。這裡要用到數字的知識,不妨按位考慮由於是& ,所以我們只用考慮區間中在該位上有多少1就行了。然後推一推關係就行。

#include

using

namespace std;

typedef

long

long ll;

const

int n=

1e5+10;

const

int m=

1e9+7;

ll a[n]

;int n,l=

32,m,opt;

struct node

}t[n<<2]

;void

build

(int now,

int l,

int r)

return;}

int mid=

(l+r)

>>1;

build

(now<<

1,l,mid)

;build

(now<<1|

1,mid+

1,r)

;for

(int j=l;j>=

0;j--

) t[now]

.b[j]

=t[now<<1]

.b[j]

+t[now<<1|

1].b[j];}

void

change

(int now,

int l,

int r,

int p,ll x)

int mid=

(l+r)

>>1;

if(p<=mid)

change

(now<<

1,l,mid,p,x);if

(mid+

1<=p)

change

(now<<1|

1,mid+

1,r,p,x)

;for

(int j=l;j>=

0;j--

) t[now]

.b[j]

=t[now<<1]

.b[j]

+t[now<<1|

1].b[j];}

node query

(int now,

int l,

int r,

int x,

int y)

int mid=

(l+r)

>>1;

// ll ans=0;node n1

node ans1=

node()

;node ans2=

node()

;if(x<=mid) ans1=

query

(now<<

1,l,mid,x,y);if

(midquery

(now<<1|

1,mid+

1,r,x,y)

;for

(int j=l;j>=

0;j--

) ans1.b[j]

+=ans2.b[j]

;return ans1;

}ll pow_mod

(ll a,

int b)

return ans;

}int

main()

else

printf

("%lld\n"

,ans);}

}}

sequence 牛客 ( 線段樹)

題面 your are given two sequences a1 n,b1 n a b a1 n b1 n you need to answer max 1 l r n displaystyle max times sum b 1 l r nmax 1e 6 b i 1e 6 1e6 1 e6 ...

牛客網 數字和為sum的方法

題目描述 給定乙個有n個正整數的陣列a和乙個整數sum,求選擇陣列a中部分數字和為sum的方案數。當兩種選取方案有乙個數字的下標不一樣,我們就認為是不同的組成方案。輸入描述 輸入為兩行 第一行為兩個正整數n 1 n 1000 sum 1 sum 1000 第二行為n個正整數ai,以空格隔開。輸出描述...

帶 sin, cos 的線段樹 牛客

題意 給你 n 個數字,第一種操作是將乙個區間內每乙個數字加上同乙個數字,第二種操作是求乙個區間內每乙個數 sin 的累加和 思路分析 對於每個區間維護一下 cos 和 sin 的值,當乙個區間要加上乙個數字時,此時再重新計算 sin的值時 sin a x sin a cos x cos a sin...