1. 程式人生 > >[51nod 1577] 異或湊數

[51nod 1577] 異或湊數

fin uri -s bsp courier 合並 復雜 ext 51nod

從左到右一共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或NO
Input示例
5
1 1 2 4 6
3
1 2 1
2 4 8
3 5 7
Output示例
YES
NO
NO




異或的問題當然是線性基了。
但是如何維護區間內的線性基呢?
線段樹不太現實, 因為線性基只能暴力合並,再加上線段樹就是三個log肯定炸了。
我們考慮一個以l為左端點的線性基, 並且每一個基存一下它出現的位置。
從後往前跑, 已經構造了i以後的線性基, 正在插入i。
如果線性基中他的位置存在一個數,就比較一下這個數的位置和i的大小關系,位置靠前的插入線性基, 位置考後的接著在線性基裏跑。
復雜度O(NlongN)。

 
#include <iostream>
#include <cstdio>
using namespace
std; #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] 異或湊數