這道題的題意十分淺顯易懂。
有一串很長很長不知道有多長(最長十萬)的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;
}
貌似這個暴力比樹狀數組還快……
應該是數據太水了。
否則應該可以卡的。