傳送門啦
傳送門啦
一般這種位運算的題都要把每一位拆開來看,因為位運算每個位的結果這和這一位的數有關。
這樣我們用s[i]表示a的字首和,即 $ a[1]+a[2]+....a[i] $ ,然後我們從這些數二進位制最右位 $ 2^0 $ 開始,按照每一位對答案的貢獻來計算。
假設我們現在算到最右位 $ 2^0 $ ,並且位於第i個數,我們想要知道以i結尾的連續和對答案的貢獻,只需要知道有多少 $ s[i]-s[j](0<=j如果這個數是奇數,就說明異或了1奇數次,也就相當於異或了1,我們只需要把記錄這一位總的異或貢獻的變數 $ cnt $ 異或1即可;
如果是偶數就不用管了,對答案沒有貢獻。
對於數的每一位如果最後 $ cnt=1 $ 的話,就說明在這一位所有連續和的異或和為1,我們就需要把答案加上(1<<(這個位數))。
那如何快速計算有多少個 $ s[i]-s[j] $ 的二進位制第k位是否為1呢??
答案是利用權值樹狀陣列。
考慮到 $ \sum a $ 最大才有1000000,我們構造兩棵權值樹狀陣列,一棵記錄當前位為1的,另一棵記錄為0的。
如果當前掃瞄到的 $ s[i] $ 的二進位制第k位為1,那麼對這一位的答案有貢獻的只有那些第k位為1且第k位向右的數比 $ s[i] $ 第k位向右的數大的或者第k位為0且第k位向右的數不比 $ s[i] $ 第k位向右的數大的。
因為如果第k位都為1的話,那麼只有後面那些位的和大於s[i]的數, $ s[i] $ 減去它之後第k位才能出現1(因為s[i]比它小的話需要向更高位借數,就和小學學的橫式減法差不多),從而對答案作出貢獻;
如果第k位為0的話,如果後面再比 $ s[i] $ 大的話, $ s[i] $ 第k位的1就需要借給低一位的了,所以後面必須不比 $ s[i] $ 大。
這樣就很好用權值樹狀陣列維護了。。。。
#include #include #include #define ll long long
#define max(a,b) (a)>(b)?(a):(b)
using namespace std;
const int maxn = 1e6 + 4;
inline int read()
while(ch >= '0' && ch <= '9')
return x * f;
}ll s[maxn],a[maxn];
ll f[2][maxn],n,m,ans=0,now,cnt=0,tmp;
bool flag;
ll maxx;
inline int lowbit(int x)
inline void update(ll x,ll y)
inline ll query(ll x,ll y)
int main()
for(ll i=0; i<=20; i++)
if(cnt) ans += (1 << i);
} cout
}
洛谷P2420 讓我們異或吧(樹上異或)
題目描述 異或是一種神奇的運算,大部分人把它總結成不進製加法.在生活中 xor運算也很常見。比如,對於乙個問題的回答,是為1,否為0.那麼 a是否是男生 xor b是否是男生 a和b是否能夠成為情侶 好了,現在我們來製造和處理一些複雜的情況。比如我們將給出一顆樹,它很高興自己有n個結點。樹的每條邊上...
洛谷 P3907 圈的異或
給出無向圖g,邊 ai,bi 的權是ci,判斷下列性質是否成立 對於任意圈c,其邊權的異或和是0 輸入格式 第1 行,1 個整數t,表示資料的組數。每組資料第1 行,2 個整數 n,m,表示圖g 點和邊的數量。m 行,每行3 個整數 ai,bi,ci,輸出格式 對每個資料輸出一行,yes 或者 no...
洛谷 P4551 最長異或路徑
首先我們知道,例如1為根,假設存在這樣三條邊 1 2,2 3,2 4,那麼,路徑 3,4 的值等於 1,3 1,4 那麼我們現在可以得到以1為端點,1到n為另一端點的n條邊,和這n條路徑的異或和值的集合s,我們現在就是要找兩個端點x,y,使路徑 x,y 的值最大,即 1,x 1,y 值最大,換而言之...