題目
正解
先求出前綴和。考慮分界點前綴和的取值。
可以發現它的取值只有種。具體證明考慮前面若干段的異或和都在集合中,所以它一定是中若干個數異或起來。
思考一下如何判定是否有答案。
如果整個序列的異或和爲,就是找到任意一個在中的前綴和。
如果整個序列的異或和不爲,假如找到一個合法前綴和等於整個序列的前綴和,那麼一定有答案。因爲這個位置到最後這段區間的異或和爲,於是這段區間就可以直接和上一段合併。
(後面值考慮異或和不爲的情況。因爲後面可以發現能夠直接用它維護的東西,求出異或和爲的答案。)
於是我們要找到這些合法的前綴和,只要有一個等於整個序列的異或和就完事了。
對於每種取值,我們求出它第一次出現的位置。這樣意味着往後轉移能有更多的選擇(強調:我們現在的目的是儘可能找到所有合法的前綴和)。
“轉移”:枚舉集合中的一個數,異或一下求出一個新的前綴和,試着在後面找。
做一個優先隊列BFS,先處理位置小的。試着去轉移到另一個前綴和,如果轉移到了,加入隊列,並且標記;如果轉移不到,還是要標記。因爲現在位置是最小的,所以現在找不到,以後也找不到。
於是現在的問題是如何在某個位置後面快速地找到一個數(前綴和)且使其儘量靠前。並且支持區間異或一個數。
這個東西顯然就是個大分塊。每個塊維護bitset
用以查詢,整塊打標記散塊暴力,這樣就可以在的時間複雜度內解決了。
還有什麼用哈希和vector
上二分,或雙關鍵字基數排序之後二分的方法,看起來感覺可能快一些,但實際並沒有什麼卵用,反而常數大會拖慢程序速度。因爲總體複雜度還是,只是局部找數字的時候快一點。然而預處理這些東西的時間遠遠超過它們能夠優化的時間……
看似優美的想法使我浪費兩個小時卡常數
代碼
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bitset>
#include <cassert>
#include <ctime>
#define N 100010
#define B 1000
#define M (N/B+5)
int input(){
char ch=getchar();
while (ch<'0' || ch>'9')
ch=getchar();
int x=0;
do{
x=x*10+ch-'0';
ch=getchar();
}
while ('0'<=ch && ch<='9');
return x;
}
int n,m;
int a[N],ps[N],all;
int k,b[5];
int bel[N],L[N],R[N];
bitset<1<<20> s[M];
int tag[M];
void build(int x){
bitset<1<<20> *sx=&s[x];
sx->reset();
for (int i=L[x];i<=R[x];++i)
sx->set(ps[i]);
}
void change(int l,int c){
int x=bel[l];
for (int i=l;i<=R[x];++i)
ps[i]^=c;
build(x);
for (int i=bel[l]+1;i<=m;++i)
tag[i]^=c;
}
int find(int x,int y,int v){
v^=tag[x];
for (int i=y;i<=R[x];++i)
if (ps[i]==v)
return i;
return 0;
}
int query(int l,int v){
if (s[bel[l]][v^tag[bel[l]]]){
int tmp=find(bel[l],l,v);
if (tmp)
return tmp;
}
for (int i=bel[l]+1;i<=m;++i)
if (s[i][v^tag[i]])
return find(i,L[i],v);
return 0;
}
bool vis[1<<20];
int h[100],nh;
bool cmph(int son,int fa){return son>fa;}
int q[100];
int BFS(){
int cnt=0;
nh=1;
h[0]=0;
vis[0]=1;
q[++cnt]=0;
while (nh){
int x=h[0];
pop_heap(h,h+nh--);
for (int i=0;i<k;++i){
int v=(ps[x]^tag[bel[x]])^b[i];
if (vis[v]==0){
vis[v]=1;
q[++cnt]=v;
int tmp=query(x+1,v);
if (tmp){
if (v==all){
for (int j=1;j<=cnt;++j)
vis[q[j]]=0;
return 1;
}
h[nh++]=tmp;
push_heap(h,h+nh,cmph);
}
}
}
}
for (int i=1;i<=cnt;++i)
vis[q[i]]=0;
return 0;
}
int main(){
freopen("contest.in","r",stdin);
freopen("contest.out","w",stdout);
n=input();
int Q=input();
for (int i=1;i<=n;++i){
a[i]=input();
ps[i]=a[i]^ps[i-1];
}
all=ps[n];
for (int i=1;i<=n;i+=B){
++m;
L[m]=i;
for (int j=i;j<i+B && j<=n;++j)
bel[j]=m,R[m]=j;
}
for (int i=1;i<=m;++i)
build(i);
while (Q--){
int op=input();
if (op==1){
int x=input(),c=input();
c=a[x]^c;
a[x]^=c;
all^=c;
change(x,c);
}
else{
k=input();
for (int i=0;i<k;++i)
b[i]=input();
sort(b,b+k);
k=unique(b,b+k)-b;
if (all){
if (BFS())
printf("yes\n");
else
printf("no\n");
}
else{
int ans=0;
for (int i=0;i<k && ans==0;++i)
ans|=query(1,b[i]);
if (ans)
printf("yes\n");
else
printf("no\n");
}
}
}
// printf("time=%d %d\n",tim,clock());
return 0;
}