考慮維護乙個這樣的問題:
(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...