P6025 線段樹 規律 模擬 位運算

2022-09-10 23:45:35 字數 1622 閱讀 8537

題意:a[i]代表維護1~i區間的線段樹建樹後陣列的最大下標,有1e15範圍內的l和r,求a[l]一直異或到a[r]的值。

分析:a[l]異或到a[r]採用從(1異或到a[l-1])異或(1異或到a[r])求出,所以只需要算1異或到a[i]即可。具體原理如何得到乙個線段樹陣列最大下標的值還沒有搞懂,但是通過樸素建樹**打表可以發現這個數值是存在規律的,並且是一種二進位制的規律,(下面的元素都是二進位制表示)除了第乙個元素為1第二個元素為11以外,從第三個元素開始存在規律,打表後用bitset輸出二進位制可以發現,維護1~4的線段樹最大下標是111,維護1~8的線段樹最大下標是1111,維護1~16的線段樹最大下標是11111,以此類推,並且維護1~3的線段樹下標是101,維護1~5的線段樹下標是1001,維護1~9的線段樹的下標是10001,以此類推,至於中間的數,6到7之間有2個1101,隨後緊接著的8是1111,10到15之間有2個11001,4個11101,隨後緊接著的16是11111,以此類推,可以發現,中間那些2的某某次方的數在異或之後全部變成0,只需要計算頭尾元素的異或值即可,這樣一來可以在log的複雜度內計算出每乙個2^k(k是正整數)的異或值,我們這裡找<=當前要求的a[i]的最大2^k,然後把它的亦或值放到貢獻裡,剩下的部分(記為remind)我們可以發現從2^k的下乙個元素開始,第乙個元素必定是100…(此處若干個0)…001,然後是2個110……001,然後是4個111……001,然後是8個……,以此類推直到最後乙個是111……111,因為第乙個元素是最特殊的,所以我們先然之前算出來的貢獻異或一下第乙個元素,然後讓remind個數-1,然後讓剩下的數只要能減就依次減去2、4、8……,因為是偶數個數異或,所以異或出來的值還是0,同時我們更新當前異或到的元素的值(記為num),直到remind不能再減了,這個時候如果remind為奇數,說明異或了奇數次的num,所以剩下的值還是num,我們只要把之前算出來的二進位制貢獻異或一下num就好了,如果remind為偶數,那說明異或了偶數次,值為0,那只要輸出之前的二進位制貢獻就好了。

1 #include 2

#define int long long

3 typedef long

long

ll;4

using

namespace

std;

5 bitset <8>bit;

6int f(int

x) else

else23}

24}25int val = 1ll <26if (x == val) return

base;27

int remind = x -val;

28base ^= ((1ll << (b+1)) +1ll);

29 bit = ((1ll << (b+1)) +1ll);

30 remind--;

31if (remind == 0) return

base;32

int cnt = 1, num = ((1ll << (b+1)) + 1ll) ^ (1ll <<(b));

33while (remind >= (1ll<;

34if (remind & 1) base ^=num;

35return

base;36

}37intl,r;

38signed main()

線段樹 構造 A 或位運算

乙個長度為 n 的非負整數序列,需要滿足 m 個區間或值為閾值的限制條件 現在要構造乙個這樣的序列,不存在輸出no 線段樹支援區間與,但查詢區間或,下傳標記,那就很好做了 include include define rr register using namespace std const int...

POJ 2777 線段樹 位運算

poj 2777 有乙個長位l的區間,有t種顏色,進行o次操作,每次操作 1 n 100000,1 t 30 1 o 100000 每次操作有兩種形式 p a b c 將區間 a,b 染成顏色c q a b 詢問區間 a,b 有多少種不同的顏色 每個點的初始顏色都是1 注意 a可能大於b 線段樹的區...

NOIP模擬 位運算(trie樹 按位貪心)

題目描述 有q次操作,每次操作是以下兩種 1 加入乙個數到集合中 2 查詢,查詢當前數字與集合中的數字的最大異或值,最大and值,最大or值 輸入格式 第一行1個正整數q表示操作次數 接下來q行,每行2個數字,第乙個數字是操作序號op 1,2 第二個數字是x表示操作的數字 輸出格式 輸出查詢次數行,...