無聊的數對
題解
好水的題呀,爲什麼還是這句話???
額,首先,我們知道要使得的__builtin_parityll(即它在二進制下1的個數是否爲奇,一下簡稱parityll爲奇的話,a與b的parityll一定是不同的。
這,還是證一下吧。
我們設有個1,有個1,它們共有的1的個數爲,那麼它們異或後的1的個數爲,它的奇偶性與是相同的,所以要使得的1個數爲奇,必定爲奇,於是與的奇偶性不同。
於是答案就成了所有區間內偶數個1的個數乘上奇數個1的個數的積。
然後,我們發現數據規模爲,明顯不能直接用暴力。我們就想到了線段樹維護所有已選的區間,加上一個動態開點就可以維護整個序列的值了。
時間複雜度是,還是不忽略32了。
源碼
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<bitset>
#include<set>
using namespace std;
#define MAXN 1000005
typedef long long LL;
#define int LL
typedef pair<int,int> pii;
#define gc() getchar()
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=gc();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
x*=f;
}
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
int n,root,tot;
int lson[MAXN],rson[MAXN];
int tag[MAXN],odd[MAXN],even[MAXN];
int cal(int x){
if(x&1LL)return x+1LL>>1LL;
return (x>>1LL)+__builtin_parityll(x);
}
int calc(int l,int r){return cal(r)-cal(l-1);}
void insert(int &rt,int l,int r,int al,int ar){
//printf("%d %d:%d %d\n",l,r,al,ar);
if(!rt)rt=++tot;
if(tag[rt])return ;
if(al<=l&&r<=ar){
rt=++tot;tag[rt]=1;
odd[rt]=calc(l,r);
even[rt]=r-l+1-odd[rt];
//printf("%d %d:%d %d\n",l,r,odd[rt],even[rt]);
return ;
}
int mid=l+r>>1LL;
if(al<=mid)insert(lson[rt],l,mid,al,ar);
if(ar>mid)insert(rson[rt],mid+1,r,al,ar);
odd[rt]=odd[lson[rt]]+odd[rson[rt]];
even[rt]=even[lson[rt]]+even[rson[rt]];
tag[rt]|=tag[lson[rt]]&tag[rson[rt]];
//printf("%d %d %d %d:%d %d\n",rt,tag[rt],l,r,odd[rt],even[rt]);
}
signed main(){
read(n);
for(int i=1;i<=n;i++){
int l,r;read(l);read(r);
insert(root,1,(1LL<<32LL),l,r);
printf("%lld\n",odd[root]*even[root]);
}
return 0;
}
/*
*/