【codevs2343】簡單題【位運算】【卡常大法好】

這道題的題意十分淺顯易懂。
有一串很長很長不知道有多長(最長十萬)的01序列,一開始全是0.

要你維護兩種操作:將一個區間內的數翻轉(就是1變0,0變1,就是異或1)、詢問某一位是0還是1.

樹狀數組的裸題啊。

但是我使用了傳說中的卡常數大法~~~

直接暴力修改,但是把64個01位壓進了一個unsigned long long。

這樣修改是O(n)的,但是常數奇小- -

不過位運算坑死我了。

~0ULL>>63是1,但是>>64又變成了~0ULL……

所以要把右一r+1位寫成>>r>>1.

假設從低位到高位是從右往左數,從第0位算起(實際讀入區間的時候要減1)。

因爲序列長10 0000,所以我們開個1600的數組d好了。

由於某種畫蛇添足的原因,我把數組下標的開始位置設成了1……

現在要把第L位到第R位翻轉。

第L位一定在d[L/64+1]即d[(L>>6)+1],同理第R位在d[(R>>6)+1]。

然後L、R對64取模(&63)就得到他們在這個64位整數裏的位置。

本來我們應該把d[(L>>6)+1]的第L&63位到第63位翻轉,把d[((L>>6)+2)..((R>>6))]翻轉,再把d[(R>>6)+1]的第0位到第R&63位翻轉。

因爲翻了兩次等於沒翻,所以我們可以先把d[(L>>6)+1]的第0位到第(L&63)-1位、d[(R>>6)+1]的第(R&63)+1位到第63位翻轉,

再for i從(L>>6)+1到(R>>6)+1,這樣就行了。

這玩意卡了我老長時間,看來我還有很長很長不知道有多長的路要走……

- -

/*
作者:ZMOIYNLP
題目:p2343 簡單題
*/
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef unsigned long long ull;
struct hehe{
	ull d[1600];
	inline void flip(int l,int r){
		int l1=(l>>6)+1,r1=(r>>6)+1;
		l&=63,r&=63;
		d[l1]^=(~0ULL)>>(63-l)>>1;
		d[r1]^=(~0ULL>>r>>1)<<(r+1);
		for(int i=l1;i<=r1;++i)
			d[i]^=~0ULL;
	}
}a;
inline void read(int &x){
	x=0;
	char ch=getchar();
	if(ch==-1) return;
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	bool flag=false;
	if(ch=='-') flag=true,ch=getchar();
	do{x=x*10+ch-48;ch=getchar();}while(ch>='0'&&ch<='9');
	if(flag) x=-x;
}
int main(){
	int n,m,t,l,r;
	read(n);read(m);
	while(m--){
		read(t);
		if(t==1){
			read(l);read(r);
			a.flip(l-1,r-1);
		}
		else{
			read(l);
			putchar(((a.d[(l-1>>6)+1]>>(l-1))&1)+48);
			putchar('\n');
		}
	}
	return 0;
}

貌似這個暴力比樹狀數組還快……

應該是數據太水了。

否則應該可以卡的。

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