【2019hdu多校第一場B題 HDU - 6579 】Operation(線性基)

There is an integer sequence aa of length n and there are two kinds of operations: 

  • 0 l r: select some numbers from al...ar so that their xor sum is maximum, and print the maximum value.
  • 1 x: append x to the end of the sequence and let n=n+1.

 

Input

There are multiple test cases. The first line of input contains an integer T(T≤10), indicating the number of test cases. 
For each test case: 
The first line contains two integers n,m(1≤n≤5×105,1≤m≤5×105), the number of integers initially in the sequence and the number of operations. 
The second line contains n integers a1,a2,...,an(0≤ai<230) , denoting the initial sequence. 
Each of the next mm lines contains one of the operations given above. 
It's guaranteed that ∑n≤106,∑m≤106,0≤x<230. 
And operations will be encrypted. You need to decode the operations as follows, where lastans denotes the answer to the last type 0 operation and is initially zero:
For every type 0 operation, let l=(l xor lastans)mod n + 1, r=(r xor lastans)mod n + 1, and then swap(l, r) if l>r. 
For every type 1 operation, let x=x xor lastans.

Output

For each type 0 operation, please output the maximum xor sum in a single line.

Sample Input

1
3 3
0 1 2
0 1 1
1 3
0 3 4

Sample Output

1
3

題意:

給n個數,m個詢問,每次詢問有兩種0 l r,代表查詢(l^ans)%n+1到(r^ans)%n+1區間內這些數中選一部分異或的最大值(放在ans中),1 x代表在序列末尾加入一個數x^ans。

思路:

當時在比賽時想過線性基,但是感覺暴力的話時間複雜度比較高。結束後跟同學討論,得知有另一種構造線性基的方式(參考 51-nod 1577)。構造思路,對於每一個數構造一個線性基,這個線性基是以他爲結尾,選他之前的並且最靠近他的元素構造的。構造方式是,從左向右遍歷數組,把第一個元素加入第一個線性基中,然後之後的線性基先繼承前一個線性基,然後再往其中加入當前位置的元素。不過這裏加元素和普通的線性基有些不同,這裏需要維護每一位的加入的元素的位置即代碼中的idx數組。加入新元素時,如果當前位置沒有元素,則直接加入,如果有元素,並且這個元素加入時間比當前元素早,就將d數組中的元素和當前要繼續插入的元素交換,順便交換加入時間。然後繼續把這個元素看看能不能在後面的位置插入進去。

查找最大值和之前的查找方式差不多,只不過需要先固定右端點,這樣就保證選的元素都是在右端點左邊的,然後貪心選的元素的同時,需要看看這個元素是不是在左區間的右邊即可。加入新的元素時需要爲其構建一個新的線性基,構造方式同上。

這裏需要注意對線性基數組的初始化,因爲T組樣例,所以只需要將lb[0]初始化,後面的是在繼承前面的基礎上,在加元素的。並且這裏讀入要從1~n讀,因爲後面詢問的l,r是1~n的。因爲是在原數組的結尾加元素,所以構造線性基是從左向右構造以某個點爲結尾的線性基(否則也可以反方向構造,51nod的那道題兩個方向都可以)。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 600000;
int a[maxn];
struct L_B{
	int d[32],idx[32],r;
	L_B(){
		memset(d,0,sizeof(d));
	}
	void clear(){
		memset(d,0,sizeof(d));
	}
	bool insert(int x,int id){
		for(int i=30;i>=0;i--){
			if(x&(1<<i)){
				if(d[i]){
					if(id>idx[i]){
						swap(idx[i],id);
						swap(d[i],x);
					}
					x^=d[i];
				}
				else{
					d[i]=x;
					idx[i]=id;
					r++;
					break;
				}
			}
		}
		return x>0;
	}
	int query_max(int l){
		int ret=0;
		for(int i=30;i>=0;i--){
			if(idx[i]>=l&&(ret^d[i])>ret)
			ret^=d[i];
		}
		return ret;
	}
}lb[maxn];
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int n,m;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++) 
		scanf("%d",&a[i]);
		lb[0].clear();
		for(int i=1;i<=n;i++){
			lb[i]=lb[i-1];
			lb[i].insert(a[i],i);
		}
		int ans=0;
		while(m--){
			int op;
			scanf("%d",&op);
			if(op==0){
				int l,r;
				scanf("%d%d",&l,&r);
				l=(l^ans)%n+1;
				r=(r^ans)%n+1;
				if(l>r) swap(l,r); 
				ans=lb[r].query_max(l);
				printf("%d\n",ans);
			}
			else{
				int tmp;
				scanf("%d",&tmp);
				tmp^=ans;
				n++;
				lb[n]=lb[n-1];
				lb[n].insert(tmp,n);
			}
		}
	}		
	return 0;
}

關於線性基構造方式證明可以參考這個博客:參考博客

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章