[51nod 1577] 異或湊數
阿新 • • 發佈:2018-08-26
fin uri -s bsp courier 合並 復雜 ext 51nod
Output示例
從左到右一共n個數,數字下標從1到n編號。
一共m次詢問,每次詢問是否能從第L個到第R個數中(包括第L個和第R個數)選出一些數使得他們異或為K。
數據量比較大。
輸入請用快速讀入
輸出請用puts
Input單組測試數據。 第一行一個整數n(0<n<=500,000)。 第二行n個整數,0<每個數<2^30。 第三行一個數m,表示詢問次數(0<m<=500,000)。 接下來m行每行三個數,L,R,K(0<L<=R<=n,0<K<2^30)。Output
M行,每行為YES或NOInput示例
5 1 1 2 4 6 3 1 2 1 2 4 8 3 5 7
YES NO NO
異或的問題當然是線性基了。
但是如何維護區間內的線性基呢?
線段樹不太現實, 因為線性基只能暴力合並,再加上線段樹就是三個log肯定炸了。
我們考慮一個以l為左端點的線性基, 並且每一個基存一下它出現的位置。
從後往前跑, 已經構造了i以後的線性基, 正在插入i。
如果線性基中他的位置存在一個數,就比較一下這個數的位置和i的大小關系,位置靠前的插入線性基, 位置考後的接著在線性基裏跑。
復雜度O(NlongN)。
#include <iostream> #include <cstdio> using namespacestd; #define reg register inline int read() { int res=0;char ch=getchar();bool flag=0; while(!isdigit(ch)) {if(ch==‘-‘)flag=1;ch=getchar();} while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48), ch=getchar(); return flag ? -res : res; } int n, a[500005]; struct Lbase {int x, id; }f[500005][31]; int main() { n = read(); for (reg int i = 1 ; i <= n ; i ++) a[i] = read(); for (reg int i = n ; i >= 1 ; i --) { memcpy(f[i], f[i+1], sizeof f[i]); Lbase now = (Lbase){a[i], i}; for (reg int j = 30 ; j >= 0 ; j --) { if (now.x >> j) { if (!f[i][j].x) swap(now, f[i][j]); else { if (f[i][j].id > now.id) swap(now, f[i][j]); now.x ^= f[i][j].x; } } } } int T = read(); while(T--) { int l = read(), r = read(); int k = read(); for (reg int i = 30 ; i >= 0 ; i --) { if ((k >> i) & 1) { if (f[l][i].id <= r and f[l][i].x) k ^= f[l][i].x; } } if (!k) puts("Yes"); else puts("No"); } return 0; }
[51nod 1577] 異或湊數